PageSourceSearch

https://builderstudio.dev/chunk-D3TUJ3FV.js

js builderstudio.dev collected 2026-10-09 22:54:26 UTC 36,984 bytes, 3 lines download raw bytes

1import{c as U}from"./chunk-NMTYPIZX.js";import"./chunk-QWWAGSPG.js";import"./chunk-NQRLHYY5.js";import"./chunk-LTHACFWH.js";import{e as q}from"./chunk-JRWJG7GL.js";import{c as R}from"./chunk-N6FP2GZP.js";import"./chunk-75IODL35.js";import{g as D,h as B}from"./chunk-7QPKAWFP.js";import"./chunk-YB5VG7XF.js";import{a as L}from"./chunk-FLEPQZ25.js";import"./chunk-G5PTU4YI.js";import{$a as c,Eb as h,La as O,Ma as E,O as v,Pa as u,Qa as g,Ra as m,S as x,Sa as e,T as A,Ta as t,Ua as d,Xb as T,Za as N,ba as b,bb as y,c as _,jb as f,ka as P,kb as S,lb as n,mb as l,ob as I,pa as r,vb as C,xa as M}from"./chunk-GLQBUVV6.js";var w=()=>["/apps/integrations"],k=(s,a)=>a.name,F=(s,a)=>a.url,V=(s,a)=>a.title;function z(s,a){if(s&1&&(e(0,"code"),n(1),t()),s&2){let i=a.$implicit;r(),l(i.name)}}function W(s,a){if(s&1&&(e(0,"a",31)(1,"span",47)(2,"strong"),n(3),t(),e(4,"small"),n(5),t()(),e(6,"span",48),n(7),t()()),s&2){let i=a.$implicit;m("href",i.sourceUrl,P),r(3),l(i.name),r(2),I("",i.label," \xB7 ",i.valuePreview),r(2),l(i.sourceLabel)}}function Y(s,a){if(s&1&&(e(0,"a",35)(1,"span",49),d(2,"i"),t(),e(3,"span",50)(4,"strong"),n(5),t(),e(6,"small"),n(7),t(),e(8,"span"),n(9),t()(),d(10,"i",51),t()),s&2){let i=a.$implicit;m("href",i.url,P),r(2),S(i.iconClass),r(3),l(i.label),r(2),l(i.domain),r(2),l(i.description)}}function j(s,a){if(s&1&&(e(0,"div",42)(1,"span",52),d(2,"i"),t(),e(3,"span")(4,"strong"),n(5),t(),e(6,"small"),n(7),t()()()),s&2){let i=a.$implicit;r(2),S(i.iconClass),r(3),l(i.title),r(2),l(i.description)}}function $(s,a){if(s&1&&(e(0,"a",31)(1,"span",47)(2,"strong"),n(3),t(),e(4,"small"),n(5),t()(),e(6,"span",48),n(7,"Optional"),t()()),s&2){let i=a.$implicit;m("href",i.sourceUrl,P),r(3),l(i.name),r(2),l(i.description)}}function J(s,a){if(s&1&&(e(0,"article",64)(1,"span",65),d(2,"i"),t(),e(3,"strong"),n(4),t(),e(5,"p"),n(6),t(),e(7,"small"),n(8),t()()),s&2){let i=a.$implicit;r(2),S(i.iconClass),r(2),l(i.title),r(2),l(i.description),r(2),l(i.label)}}function H(s,a){if(s&1){let i=N();e(0,"div",53),c("click",function(){x(i);let p=y();return A(p.showWorkflowModal.set(!1))}),e(1,"section",54),c("click",function(p){return p.stopPropagation()}),e(2,"header",55)(3,"div")(4,"span"),n(5,"How this works"),t(),e(6,"h2"),n(7,"Notification flow"),t(),e(8,"p"),n(9,"Save APNS secrets, generate the server, deploy it, then verify delivery without keeping the full process pinned on the page."),t()(),e(10,"button",56),c("click",function(){x(i);let p=y();return A(p.showWorkflowModal.set(!1))}),d(11,"i",57),t()(),e(12,"div",58),d(13,"span",59)(14,"span",60)(15,"span",61)(16,"span",62)(17,"span",63),u(18,J,9,5,"article",64,V),t()()()}if(s&2){let i=y();r(18),g(i.workflowSteps)}}var K=class s{constructor(){this.authService=v(q);this.seoService=v(L);this.appToastService=v(R);this.router=v(D);this.isSuperAdmin=h(()=>this.authService.isSuperAdmin());this.platformAccountLabel=h(()=>this.authService.profile()?.username||this.authService.currentUser()?.email||"account");this.showWorkflowModal=b(!1);this.selectedEnvironment=b("production");this.selectedProviderPath=b("direct-apns");this.builderPromptCopied=b(!1);this.apnsIntegrationQueryParams={setup:"apns-notifications",category:"communications",integration:"apple-apns",search:"APNS"};this.apnsVaultSecretNames=["APNS_TEAM_ID","APNS_KEY_ID","APNS_PRIVATE_KEY","APNS_BUNDLE_ID","APNS_ENVIRONMENT"];this.setupResources=[{label:"Apple Developer Account",url:"https://developer.apple.com/account/",description:"Start here for Certificates, Identifiers & Profiles, APNs keys, Bundle IDs, and Team ID.",domain:"developer.apple.com",iconClass:"ph ph-apple-logo"},{label:"Apple Keys",url:"https://developer.apple.com/account/resources/authkeys/list",description:"Create or find the APNs Auth Key. Download the .p8 key once and copy the Key ID.",domain:"developer.apple.com",iconClass:"ph ph-key"},{label:"Apple Identifiers",url:"https://developer.apple.com/account/resources/identifiers/list",description:"Create or open the app Bundle ID and enable the Push Notifications capability.",domain:"developer.apple.com",iconClass:"ph ph-fingerprint"},{label:"Apple Membership",url:"https://developer.apple.com/account/#/membership",description:"Find the Team ID used by APNs token authentication.",domain:"developer.apple.com",iconClass:"ph ph-identification-card"},{label:"App Store Connect",url:"https://appstoreconnect.apple.com/apps",description:"Confirm the app record, Bundle ID, and release channel that should receive production push notifications.",domain:"appstoreconnect.apple.com",iconClass:"ph ph-storefront"},{label:"Firebase Console",url:"https://console.firebase.google.com/",de
1scription:"Optional path if the app uses FCM as a broker for iOS, Android, or cross-platform notifications.",domain:"console.firebase.google.com",iconClass:"ph ph-fire"},{label:"Expo Dashboard",url:"https://expo.dev/accounts",description:"Optional path if the mobile app uses Expo/EAS credentials and Expo push tokens.",domain:"expo.dev",iconClass:"ph ph-device-mobile"},{label:"OneSignal Dashboard",url:"https://dashboard.onesignal.com/apps",description:"Optional migration or comparison path if the customer already uses OneSignal.",domain:"dashboard.onesignal.com",iconClass:"ph ph-bell-ringing"}];this.secretRequirements=[{name:"APNS_TEAM_ID",label:"Apple Team ID",valuePreview:"1A2B3C4D5E",required:!0,description:"The Apple Developer Team ID from membership information.",sourceLabel:"Apple Membership",sourceUrl:"https://developer.apple.com/account/#/membership"},{name:"APNS_KEY_ID",label:"APNs Key ID",valuePreview:"ABC123DEFG",required:!0,description:"The 10-character key identifier attached to the APNs .p8 key.",sourceLabel:"Apple Keys",sourceUrl:"https://developer.apple.com/account/resources/authkeys/list"},{name:"APNS_PRIVATE_KEY",label:"APNs private key",valuePreview:"-----BEGIN PRIVATE KEY----- ...",required:!0,description:"The private .p8 APNs signing key contents. Users download this once from Apple Keys.",sourceLabel:"Apple Keys",sourceUrl:"https://developer.apple.com/account/resources/authkeys/list"},{name:"APNS_BUNDLE_ID",label:"App Bundle ID",valuePreview:"com.company.app",required:!0,description:"The iOS app topic used when sending APNs notifications.",sourceLabel:"Apple Identifiers",sourceUrl:"https://developer.apple.com/account/resources/identifiers/list"},{name:"APNS_ENVIRONMENT",label:"APNs environment",valuePreview:"production or sandbox",required:!0,description:"Production for App Store/TestFlight builds, sandbox for development builds.",sourceLabel:"BuilderStudio selection",sourceUrl:"https://developer.apple.com/documentation/usernotifications/establishing-a-token-based-connection-to-apns"},{name:"PUSH_SERVER_API_KEY",label:"Server API key",valuePreview:"ship_live_...",required:!0,description:"A customer-owned key that protects send, broadcast, and admin endpoints.",sourceLabel:"Generated by BuilderStudio",sourceUrl:"https://ship.you/apps/notifications"},{name:"DATABASE_URL",label:"Database URL",valuePreview:"postgresql://...",required:!0,description:"Stores registered device tokens, platform metadata, notification audit logs, and opt-out state.",sourceLabel:"BuilderStudio managed database",sourceUrl:"https://ship.you/apps/database"},{name:"ALLOWED_ORIGINS",label:"Allowed origins",valuePreview:"https://app.example.com",required:!1,description:"Optional CORS allowlist for dashboards or app backends that call this notification service.",sourceLabel:"Customer app URLs",sourceUrl:"https://ship.you/apps/domains"},{name:"FIREBASE_SERVICE_ACCOUNT_JSON",label:"Firebase service account JSON",valuePreview:'{ "type": "service_account" }',required:!1,description:"Only needed when adding Android/Web FCM or FCM-brokered iOS delivery.",sourceLabel:"Firebase Console",sourceUrl:"https://console.firebase.google.com/"},{name:"EXPO_ACCESS_TOKEN",label:"Expo access token",valuePreview:"expo_...",required:!1,description:"Only needed when routing notifications through Expo push tokens and EAS credentials.",sourceLabel:"Expo Dashboard",sourceUrl:"https://expo.dev/accounts"}];this.serverCapabilities=[{title:"Device registry",description:"REST endpoints for registering, refreshing, disabling, and deleting device tokens per user and app installation.",iconClass:"ph ph-device-mobile-camera"},{title:"Direct APNs delivery",description:"Token-based APNs HTTP/2 delivery using the .p8 key, Team ID, Key ID, Bundle ID, and environment.",iconClass:"ph ph-paper-plane-tilt"},{title:"Admin send API",description:"Protected send and broadcast endpoints with payload validation, idempotency keys, rate limits, and audit logs.",iconClass:"ph ph-shield-check"},{title:"Delivery observability",description:"Tracks accepted, failed, invalid-token, retry, and suppression events so users can debug push issues quickly during testing.",iconClass:"ph ph-chart-line-up"}];this.workflowSteps=[{label:"Step 1",title:"Collect Apple credentials",description:"The customer opens Apple Developer, enables Push Notifications on the Bundle ID, creates an APNs Auth Key, and copies Team ID, Key ID, Bundle ID, and the .p8 file contents.",iconClass:"ph ph-apple-logo"},{label:"Step 2",title:"Attach secrets in BuilderStudio",description:"Secrets are added to the managed app vault, not pasted into normal chat. BuilderStudio references secret names only.",iconClass:"ph ph-lock-key"},{label:"Step 3",title:"Generate the managed server",description:"BuilderStudio receives a prebuilt APNS server prompt with required endpoints, Docker health checks, schema, queue behavior, and deployment c
1onstraints.",iconClass:"ph ph-hammer"},{label:"Step 4",title:"Deploy and test",description:"BuilderStudio deploys the server, checks /health, then users register a test device token and send a test notification before going live.",iconClass:"ph ph-rocket-launch"}];this.requiredSecrets=h(()=>this.secretRequirements.filter(a=>a.required));this.optionalSecrets=h(()=>this.secretRequirements.filter(a=>!a.required));this.apnsVaultSecrets=h(()=>this.secretRequirements.filter(a=>this.apnsVaultSecretNames.includes(a.name)));this.generatedBuilderPrompt=h(()=>{let a=this.selectedEnvironment()==="production"?"production":"sandbox";return["Build and deploy a managed APNS push notification server for a BuilderStudio user testing the managed notifications path.","","Product goal:","Create a production-ready push notification backend that hides the hard APNs setup work behind a simple managed service. The app should be deployable on BuilderStudio as a Dockerized service with a health endpoint and clear secret names.","",`Primary provider path: ${this.selectedProviderPath()}`,`APNs environment: ${a}`,"","Required runtime:","- Node.js with TypeScript, Fastify or Express, and a root-level Dockerfile.","- Listen on 0.0.0.0 and the PORT environment variable, defaulting to 8080.","- Include GET /health returning JSON with service, status, version, APNs environment, and uptime.","- Include structured JSON logs and never log secret values or full device tokens.","","Required API endpoints:","- POST /api/push/devices/register to save a userId, installationId, platform, environment, appVersion, and deviceToken.","- POST /api/push/devices/unregister to disable a token or installation.","- POST /api/push/notifications/send to send one notification to one user, installation, or token.","- POST /api/push/notifications/broadcast to send a campaign-style message to a filtered audience.","- GET /api/push/notifications/:notificationId to inspect delivery status and provider responses.","- POST /api/push/test to send a safe test notification to a supplied token in the selected APNs environment.","","Required secrets and environment variables:","- APNS_TEAM_ID","- APNS_KEY_ID","- APNS_PRIVATE_KEY","- APNS_BUNDLE_ID","- APNS_ENVIRONMENT","- PUSH_SERVER_API_KEY","- DATABASE_URL","- ALLOWED_ORIGINS","","Optional cross-platform secrets:","- FIREBASE_SERVICE_ACCOUNT_JSON for FCM Android/Web or FCM-brokered iOS delivery.","- EXPO_ACCESS_TOKEN for Expo push token delivery.","","Secret vault requirements:","- Assume APNS_TEAM_ID, APNS_KEY_ID, APNS_PRIVATE_KEY, APNS_BUNDLE_ID, and APNS_ENVIRONMENT are saved in BuilderStudio Integrations under Comms -> Apple Push Notification service.","- The generated app should reference environment variable names only and should not ask users to paste secret values into chat.","","Security requirements:","- Require PUSH_SERVER_API_KEY for send, broadcast, status, and test endpoints.","- Validate all request bodies with explicit schemas.","- Add rate limiting for send, broadcast, register, and test endpoints.","- Support idempotency keys on send and broadcast calls.","- Store only hashed or redacted token previews in logs.","- Never expose APNS_PRIVATE_KEY through any response, page, or log.","","Data model:","- DeviceToken table with userId, installationId, platform, environment, tokenHash, encryptedToken, enabled, lastSeenAt, invalidatedAt, appVersion, locale, timezone, and metadataJson.","- Notification table with title, body, payloadJson, audienceJson, status, createdBy, createdAt, sentAt, completedAt, errorSummary, and idempotencyKey.","- NotificationDelivery table with notificationId, deviceTokenId, provider, providerMessageId, status, attemptCount, lastAttemptAt, errorCode, errorMessage, and responseJson.","","APNs behavior:","- Use token-based APNs authentication with the .p8 key, Key ID, Team ID, Bundle ID topic, and selected APNs environment.","- Support alert title/body, badge, sound, category, thread-id, mutable-content, content-available, and custom data payload.","- Handle APNs invalid token responses by disabling the affected token.","- Retry transient provider failures with bounded backoff.","","Dashboard requirements:","- Include a small admin page or JSON-ready endpoints for viewing setup status, registered devices, recent sends, and failures.","- Include a setup checklist page that shows missing env vars by name only.","- Include curl examples for registering a device and sending a test notification.","","Deployment requirements:","- Add README.md with BuilderStudio deployment steps and secret setup instructions.","- Keep Dockerfile at the project root.","- Add package scripts for build, start, dev, and test.","- Include basic unit tests for payload validation and token redaction helpers.","- Return a complete source bundle that can be deployed directly on BuilderStudio.","","User-facing setup links that should appear in README:","- Apple Developer Account: https://developer.apple.com/account/","- Apple Keys: https://developer.apple.com/account/resources/authkeys/list","- Apple Identifiers: https://developer.apple.com/account/resources/identifiers/list","- Apple Membership: https://developer.apple.com/account/#/membership","- BuilderStudio APNS secret vault: https://ship.you/apps/integrations?setup=apns-notifications&category=communications&integration=apple-apns&search=APNS","- App Store Connect: https://appstoreconnect.apple.com/apps","- Firebase Console: https://console.firebase.google.com/","- Expo Dashboard: https://expo.dev/accounts"].join(`
2`)});this.seoService.updatePageSeo({title:"APNS & Notifications",description:"Configure and deploy a managed APNS push notification server from BuilderStudio with Apple secrets, provider links, and production-ready deployment requirements.",canonicalPath:"/apps/notifications"})}setProviderPath(a){this.selectedProviderPath.set(a),this.builderPromptCopied.set(!1)}setEnvironment(a){this.selectedEnvironment.set(a),this.builderPromptCopied.set(!1)}copyBuilderPrompt(){return _(this,null,function*(){if(!(yield this.copyTextToClipboard(this.generatedBuilderPrompt()))){this.appToastService.show("Could not copy the APNS BuilderStudio prompt in this browser.","warning");return}this.builderPromptCopied.set(!0),this.appToastService.show("APNS server prompt copied for BuilderStudio.","success")})}copySecretNames(){return _(this,null,function*(){if(!(yield this.copyTextToClipboard(this.apnsVaultSecrets().map(i=>i.name).join(`
3`)))){this.appToastService.show("Could not copy the APNS vault secret names in this browser.","warning");return}this.appToastService.show("APNS vault secret names copied.","success")})}sendPromptToBuilderStudio(){return _(this,null,function*(){let a=this.getBrowserLocalStorage();a&&(a.setItem("ship.you.builderStudio.pendingPrompt",this.generatedBuilderPrompt()),a.setItem("ship.you.builderStudio.pendingName","Managed APNS Notification Server"),a.setItem("ship.you.builderStudio.pendingSlug","managed-apns-notifications"),a.setItem("ship.you.builderStudio.pendingDescription","A Docker-ready APNS push notification server with device token registration, protected send endpoints, delivery logs, and BuilderStudio secret references.")),yield this.copyBuilderPrompt(),this.router.navigateByUrl("/apps/studio")})}copyTextToClipboard(a){return _(this,null,function*(){try{return typeof navigator>"u"||!navigator.clipboard?.writeText?!1:(yield navigator.clipboard.writeText(a),!0)}catch(i){return!1}})}getBrowserLocalStorage(){try{return typeof globalThis>"u"||typeof globalThis.localStorage>"u"?null:globalThis.localStorage}catch(a){return null}}static{this.\u0275fac=function(i){return new(i||s)}}static{this.\u0275cmp=M({type:s,selectors:[["app-apns-notifications-page"]],decls:142,vars:24,consts:[["activePath","/apps/notifications","workspaceMeta","Integrations","pageTitle","Notifications",3,"accountLabel","isSuperAdmin","contentWide"],["platformTopbarActions",""],["type","button",1,"platform-button","platform-button--ghost",3,"click"],["routerLink","/apps/studio",1,"platform-button","platform-button--ghost"],[1,"platform-button","platform-button--ghost",3,"routerLink","queryParams"],["type","button",1,"platform-button","platform-button--primary",3,"click"],["aria-hidden","true",1,"ph","ph-magic-wand"],[1,"apns-page"],[1,"apns-hero"],["aria-hidden","true",1,"apns-hero__mark"],[1,"ph","ph-bell-ringing"],[1,"apns-hero__copy"],[1,"platform-card","apns-panel","apns-vault-handoff"],[1,"apns-vault-handoff__copy"],["aria-label","APNS vault environment variable names",1,"apns-vault-handoff__names"],[1,"apns-vault-handoff__actions"],[1,"platform-button","platform-button--primary",3,"routerLink","queryParams"],["aria-hidden","true",1,"ph","ph-lock-key"],[1,"apns-grid","apns-grid--two"],[1,"platform-card","apns-panel","apns-build-card"],[1,"platform-card-header"],[1,"platform-card-title"],[1,"platform-card-copy"],[1,"apns-badge"],["aria-label","Notification provider path",1,"apns-option-group"],["type","button",1,"apns-option",3,"click"],["aria-label","APNs environment",1,"apns-environment-toggle"],["type","button",3,"click"],[1,"apns-builder-summary"],[1,"platform-card","apns-panel","apns-secret-card"],[1,"apns-secret-list"],["target","_blank","rel","noopener",1,"apns-secret-row",3,"href"],[1,"apns-secret-card__actions"],[1,"platform-card","apns-panel"],[1,"apns-resource-grid"],["target","_blank","rel","noopener",1,"apns-resource-card",3,"href"],[1,"platform-card","apns-panel","apns-accordion"],[1,"apns-accordion__summary"],["aria-hidden","true",1,"ph","ph-caret-down"],[1,"apns-grid","apns-grid--two","apns-accordion__content"],[1,"apns-accordion-card"],[1,"apns-capability-list"],[1,"apns-capability-row"],[1,"apns-secret-list","apns-secret-list--optional"],[1,"platform-card","apns-panel","apns-prompt-panel","apns-accordion"],[1,"apns-accordion__prompt-header"],["role","presentation",1,"integration-process-modal-backdrop"],[1,"apns-secret-row__main"],[1,"apns-secret-row__source"],["aria-hidden","true",1,"apns-resource-card__icon"],[1,"apns-resource-card__content"],["aria-hidden","true",1,"ph","ph-arrow-square-out"],["aria-hidden","true",1,"apns-capability-row__icon"],["role","presentation",1,"integration-process-modal-backdrop",3,"click"],["role","dialog","aria-modal","true","aria-label","How this works",1,"integration-process-modal",3,"click"],[1,"integration-process-modal__header"],["type","button","aria-label","Close",1,"integration-process-modal__close",3,"click"],["aria-hidden","true",1,"ph","ph-x"],[1,"integration-flow","integration-flow--modal"],["aria-hidden","true",1,"integration-flow__grid"],["aria-hidden","true",1,"integration-flow__track"],["aria-hidden","true",1,"integration-flow__track-dot","
3integration-flow__track-dot--one"],["aria-hidden","true",1,"integration-flow__track-dot","integration-flow__track-dot--two"],["aria-hidden","true",1,"integration-flow__track-dot","integration-flow__track-dot--three"],[1,"integration-flow-step"],["aria-hidden","true",1,"integration-flow-step__icon"]],template:function(i,o){i&1&&(e(0,"app-platform-console-layout",0)(1,"div",1)(2,"button",2),c("click",function(){return o.showWorkflowModal.set(!0)}),n(3,"How this works"),t(),e(4,"a",3),n(5,"Code IDE"),t(),e(6,"a",4),n(7,"Save APNS secrets"),t(),e(8,"button",5),c("click",function(){return o.sendPromptToBuilderStudio()}),d(9,"i",6),e(10,"span"),n(11,"Build APNS server"),t()()(),e(12,"div",7)(13,"section",8)(14,"div",9),d(15,"i",10),t(),e(16,"div",11)(17,"span"),n(18,"Push Delivery"),t(),e(19,"h1"),n(20,"Notifications"),t()()(),e(21,"section",12)(22,"div",13)(23,"h2"),n(24,"Save APNS secrets before building the server"),t(),e(25,"p"),n(26,"Open Integrations with "),e(27,"strong"),n(28,"Comms \u2192 Apple Push Notification service"),t(),n(29," already selected. Users paste the Apple values once, save them to the encrypted backend vault, and BuilderStudio only uses the secret names during future builds and deploys."),t(),e(30,"div",14),u(31,z,2,1,"code",null,k),t()(),e(33,"div",15)(34,"a",16),d(35,"i",17),e(36,"span"),n(37,"Open APNS vault fields"),t()(),e(38,"button",2),c("click",function(){return o.copySecretNames()}),n(39,"Copy names"),t()()(),e(40,"section",18)(41,"article",19)(42,"div",20)(43,"div")(44,"h2",21),n(45,"Preconfigured server path"),t(),e(46,"p",22),n(47,"BuilderStudio receives a complete deployment prompt and uses secret names instead of exposing private values in chat."),t()(),e(48,"span",23),n(49,"Managed service"),t()(),e(50,"div",24)(51,"button",25),c("click",function(){return o.setProviderPath("direct-apns")}),e(52,"strong"),n(53,"Direct APNs"),t(),e(54,"span"),n(55,"Best default for native iOS apps."),t()(),e(56,"button",25),c("click",function(){return o.setProviderPath("firebase")}),e(57,"strong"),n(58,"Firebase bridge"),t(),e(59,"span"),n(60,"Add Android/Web or FCM-brokered delivery later."),t()(),e(61,"button",25),c("click",function(){return o.setProviderPath("expo")}),e(62,"strong"),n(63,"Expo path"),t(),e(64,"span"),n(65,"Use when mobile apps rely on Expo push tokens."),t()()(),e(66,"div",26)(67,"button",27),c("click",function(){return o.setEnvironment("production")}),n(68,"Production"),t(),e(69,"button",27),c("click",function(){return o.setEnvironment("sandbox")}),n(70,"Sandbox"),t()(),e(71,"div",28)(72,"strong"),n(73,"BuilderStudio will generate"),t(),e(74,"p"),n(75,"A Docker-ready TypeScript notification service with APNs token auth, register/send/broadcast/test endpoints, database schema, health checks, secret placeholders, README setup links, and delivery audit logs."),t()()(),e(76,"article",29)(77,"div",20)(78,"div")(79,"h2",21),n(80,"APNS vault fields"),t(),e(81,"p",22),n(82,"These are the exact fields users save under Comms \u2192 Apple Push Notification service in Integrations."),t()(),e(83,"button",2),c("click",function(){return o.copySecretNames()}),n(84,"Copy names"),t()(),e(85,"div",30),u(86,W,8,5,"a",31,k),t(),e(88,"div",32)(89,"a",16),n(90,"Save these in Integrations"),t()()()(),e(91,"section",33)(92,"div",20)(93,"div")(94,"h2",21),n(95,"Where to generate configuration"),t(),e(96,"p",22),n(97,"Show the exact official places users need so setup does not feel like APNs guesswork."),t()(),e(98,"span",23),n(99,"Links & domains"),t()(),e(100,"div",34),u(101,Y,11,6,"a",35,F),t()(),e(103,"details",36)(104,"summary",37)(105,"span"),n(106,"Server requirements and optional add-ons"),t(),d(107,"i",38),t(),e(108,"div",39)(109,"article",40)(110,"div",20)(111,"div")(112,"h2",21),n(113,"Server requirements"),t(),e(114,"p",22),n(115,"The generated app should be a real managed backend, not just a note about APNs."),t()()(),e(116,"div",41),u(117,j,8,4,"div",42,V),t()(),e(119,"article",40)(120,"div",20)(121,"div")(122,"h2",21),n(123,"Optional add-ons"),t(),e(124,"p",22),n(125,"Keep APNs simple first, but expose optional paths for cross-platform customers."),t()()(),e(126,"div",43),u(127,$,8,3,"a",31,k),t()()()(),e(129,"details",44)(130,"summary",37)(131,"span"),n(132,"BuilderStudio prompt preview"),t(),d(133,"i",38),t(),e(134,"div",45)(135,"p",22),n(136,"This is the prompt that gets copied and preloaded when users click Auto-fill BuilderStudio."),t(),e(137,"button",2),c("click",function(){return o.copyBuilderPrompt()}),n(138,"Copy prompt"),t()(),e(139,"pre"),n(140),t()(),O(141,H,20,0,"div",46),t()()),i&2&&(m("accountLabel",o.platformAccountLabel())("isSuperAdmin",o.isSuperAdmin())("contentWide",!0),r(6),m("routerLink",C(21,w))("queryParams",o.apnsIntegrationQueryParams),r(25),g(o.apnsVaultSecrets()),r(3),m("routerLink",C(22,w))("queryParams",o.apnsIntegrationQueryParams),r(17),f("apns-option--active",o.selectedProviderPath()==="direct-apns"),r(5),f("apns-option--active",o.selectedProviderPath()==="firebase"),r(5),f("apns-option--active",o.selectedProviderPath()==="expo"),r(6),f("apns-environment-toggle__button--active",o.selectedEnvironment()==="production"),r(2),f("apns-environment-toggle__button--active",o.selectedEnvironment()==="sandbox"),r(17),g(o.apnsVaultSecrets()),r(3),m("routerLink",C(23,w))("queryParams",o.apnsIntegrationQueryParams),r(12),g(o.setupResources),r(16),g(o.serverCapabilities),r(10),g(o.optionalSecrets()),r(13),l(o.generatedBuilderPrompt()),r(),E(o.showWorkflowModal()?141:-1))},dependencies:[T,B,U],styles:[".apns-page[_ngcontent-%COMP%]{display:grid;gap:1rem}.apns-hero[_ngcontent-%COMP%]{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:1rem;align-items:center;padding:1.25rem}.apns-hero__mark[_ngcontent-%COMP%], .apns-resource-card__icon[_ngcontent-%COMP%], .apns-step-card__icon[_ngcontent-%COMP%], .apns-capability-row__icon[_ngcontent-%COMP%]{display:grid;place-items:center;width:3.2rem;height:3.2rem;border-radius:1rem;background:radial-gradient(circle at 50% 30%,rgba(59,130,246,.34),transparent 60%),color-mix(in srgb,var(--platform-panel-strong) 88%,transparent);color:var(--platform-text);box-shadow:inset 0 1px color-mix(in srgb,var(--platform-text) 10%,transparent);font-size:1.35rem}.apns-hero__copy[_ngcontent-%COMP%]   span[_ngcontent-%COMP%], .apns-step-card__label[_ngcontent-%COMP%], .apns-badge[_ngcontent-%COMP%]{display:inline-flex;color:var(--platform-muted);font-size:.72rem;font-weight:850;letter-spacing:.08em;text-transform:uppercase}.apns-hero__copy[_ngcontent-%COMP%]   h1[_ngcontent-%COMP%]{margin:.25rem 0 0;color:var(--platform-text);font-size:clamp(1.8rem,4vw,2.8rem);font-weight:850;letter-spacing:-.07em;line-height:1.02}.apns-hero__copy[_ngcontent-%COMP%]   p[_ngcontent-%COMP%], .apns-builder-summary[_ngcontent-%COMP%]   p[_ngcontent-%COMP%], .apns-step-card[_ngcontent-%COMP%]   p[_ngcontent-%COMP%], .apns-resource-card[_ngcontent-%COMP%]   span[_ngcontent-%COMP%]   span[_ngcontent-%COMP%], .apns-capability-row[_ngcontent-%COMP%]   small[_ngcontent-%COMP%], .apns-secret-row[_ngcontent-%COMP%]   small[_ngcontent-%COMP%]{color:var(--platform-muted);font-size:.88rem;line-height:1.55}.apns-hero__copy[_ngcontent-%COMP%]   p[_ngcontent-%COMP%]{margin:.55rem 0 0;max-width:58rem}.apns-hero__actions[_ngcontent-%COMP%]{display:flex;gap:.6rem;
3align-items:center;justify-content:flex-end;flex-wrap:wrap}.apns-grid[_ngcontent-%COMP%]{display:grid;gap:1rem}.apns-grid--two[_ngcontent-%COMP%]{grid-template-columns:repeat(2,minmax(0,1fr))}.apns-grid--four[_ngcontent-%COMP%]{grid-template-columns:repeat(4,minmax(0,1fr))}.apns-panel[_ngcontent-%COMP%]{padding:1rem}.apns-badge[_ngcontent-%COMP%]{align-items:center;border-radius:999px;padding:.32rem .62rem;background:color-mix(in srgb,#3b82f6 12%,var(--platform-panel-strong));color:color-mix(in srgb,#bfdbfe 70%,var(--platform-text))}.apns-option-group[_ngcontent-%COMP%]{display:grid;gap:.7rem;margin-top:1rem}.apns-option[_ngcontent-%COMP%]{display:grid;gap:.24rem;width:100%;border:0;border-radius:1rem;background:color-mix(in srgb,var(--platform-panel-strong) 75%,transparent);color:var(--platform-text);padding:.9rem;text-align:left;cursor:pointer}.apns-option[_ngcontent-%COMP%]   span[_ngcontent-%COMP%]{color:var(--platform-muted);font-size:.82rem;line-height:1.45}.apns-option--active[_ngcontent-%COMP%]{background:linear-gradient(135deg,color-mix(in srgb,#2563eb 32%,var(--platform-panel-strong)),color-mix(in srgb,#60a5fa 16%,var(--platform-panel)));box-shadow:inset 0 1px color-mix(in srgb,#bfdbfe 25%,transparent),0 18px 40px color-mix(in srgb,#1d4ed8 14%,transparent)}.apns-environment-toggle[_ngcontent-%COMP%]{display:inline-grid;grid-template-columns:repeat(2,auto);gap:.35rem;margin-top:1rem;border-radius:999px;background:color-mix(in srgb,var(--platform-panel-strong) 80%,transparent);padding:.28rem}.apns-environment-toggle[_ngcontent-%COMP%]   button[_ngcontent-%COMP%]{border:0;border-radius:999px;background:transparent;color:var(--platform-muted);padding:.45rem .8rem;font-weight:800;cursor:pointer}.apns-environment-toggle__button--active[_ngcontent-%COMP%]{background:#2563eb!important;color:#fff!important}.apns-builder-summary[_ngcontent-%COMP%]{margin-top:1rem;border-radius:1rem;background:color-mix(in srgb,#3b82f6 9%,var(--platform-panel-strong));padding:.9rem}.apns-builder-summary[_ngcontent-%COMP%]   p[_ngcontent-%COMP%]{margin:.35rem 0 0}.apns-secret-list[_ngcontent-%COMP%], .apns-capability-list[_ngcontent-%COMP%]{display:grid;gap:.65rem;margin-top:1rem}.apns-secret-row[_ngcontent-%COMP%], .apns-resource-card[_ngcontent-%COMP%], .apns-capability-row[_ngcontent-%COMP%]{display:grid;gap:.75rem;
3align-items:center;border-radius:1rem;background:color-mix(in srgb,var(--platform-panel-strong) 78%,transparent);color:var(--platform-text);text-decoration:none}.apns-secret-row[_ngcontent-%COMP%]{grid-template-columns:minmax(0,1fr) auto;padding:.82rem}.apns-secret-row__main[_ngcontent-%COMP%]{display:grid;gap:.24rem;min-width:0}.apns-secret-row__main[_ngcontent-%COMP%]   strong[_ngcontent-%COMP%], .apns-capability-row[_ngcontent-%COMP%]   strong[_ngcontent-%COMP%], .apns-resource-card[_ngcontent-%COMP%]   strong[_ngcontent-%COMP%], .apns-step-card[_ngcontent-%COMP%]   h3[_ngcontent-%COMP%]{color:var(--platform-text);font-size:.95rem}.apns-secret-row__source[_ngcontent-%COMP%]{border-radius:999px;background:color-mix(in srgb,#2563eb 15%,var(--platform-panel));color:color-mix(in srgb,#bfdbfe 70%,var(--platform-text));padding:.3rem .55rem;font-size:.68rem;font-weight:850;white-space:nowrap}.apns-resource-grid[_ngcontent-%COMP%]{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:.75rem;margin-top:1rem}.apns-resource-card[_ngcontent-%COMP%]{grid-template-columns:auto minmax(0,1fr) auto;align-items:start;padding:.9rem}.apns-resource-card__content[_ngcontent-%COMP%]{display:grid;gap:.28rem}.apns-resource-card__content[_ngcontent-%COMP%]   small[_ngcontent-%COMP%]{color:color-mix(in srgb,#60a5fa 62%,var(--platform-muted));font-size:.75rem;font-weight:850}.apns-step-card[_ngcontent-%COMP%]{display:grid;gap:.65rem;padding:1rem}.apns-step-card[_ngcontent-%COMP%]   h3[_ngcontent-%COMP%], .apns-step-card[_ngcontent-%COMP%]   p[_ngcontent-%COMP%]{margin:0}.apns-capability-row[_ngcontent-%COMP%]{grid-template-columns:auto minmax(0,1fr);padding:.85rem}.apns-capability-row[_ngcontent-%COMP%]   span[_ngcontent-%COMP%]:last-child{display:grid;gap:.22rem}.apns-prompt-panel[_ngcontent-%COMP%]   pre[_ngcontent-%COMP%]{max-height:32rem;overflow:auto;border-radius:1rem;border:1px solid var(--platform-line-soft);background:var(--platform-bg);color:var(--platform-text);padding:1rem;white-space:pre-wrap;font-size:.78rem;line-height:1.55}@media(max-width:1180px){.apns-grid--four[_ngcontent-%COMP%], .apns-resource-grid[_ngcontent-%COMP%]{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:820px){.apns-hero[_ngcontent-%COMP%], .apns-grid--two[_ngcontent-%COMP%], .apns-grid--four[_ngcontent-%COMP%], .apns-resource-grid[_ngcontent-%COMP%]{grid-template-columns:1fr}.apns-hero__actions[_ngcontent-%COMP%]{justify-content:flex-start}}.apns-vault-handoff[_ngcontent-%COMP%]{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:1rem;border-color:color-mix(in srgb,#2563eb 34%,var(--platform-line));background:linear-gradient(135deg,color-mix(in srgb,#2563eb 12%,var(--platform-panel)),var(--platform-panel-strong))}.apns-vault-handoff__copy[_ngcontent-%COMP%]{display:grid;gap:.55rem;min-width:0}.apns-vault-handoff__copy[_ngcontent-%COMP%]   h2[_ngcontent-%COMP%]{margin:0;color:var(--platform-text);font-size:1.25rem;font-weight:820;letter-spacing:-.045em}.apns-vault-handoff__copy[_ngcontent-%COMP%]   p[_ngcontent-%COMP%]{margin:0;max-width:68rem;color:var(--platform-muted);font-size:.9rem;line-height:1.65}.apns-vault-handoff__names[_ngcontent-%COMP%]{display:flex;flex-wrap:wrap;gap:.45rem}.apns-vault-handoff__names[_ngcontent-%COMP%]   code[_ngcontent-%COMP%]{border-radius:999px;background:color-mix(in srgb,var(--platform-panel-strong) 82%,transparent);color:var(--platform-text);padding:.38rem .58rem;font-size:.72rem;font-weight:800}.apns-vault-handoff__actions[_ngcontent-%COMP%], .apns-secret-card__actions[_ngcontent-%COMP%]{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:.5rem}.apns-secret-card__actions[_ngcontent-%COMP%]{margin-top:.85rem}@media(max-width:820px){.apns-vault-handoff[_ngcontent-%COMP%]{grid-template-columns:1fr}.apns-vault-handoff__actions[_ngcontent-%COMP%], .apns-secret-card__actions[_ngcontent-%COMP%]{justify-content:flex-start}}.apns-hero[_ngcontent-%COMP%]{grid-template-columns:auto minmax(0,1fr);align-items:center;gap:1rem;padding:.25rem 0 .5rem}.apns-hero__mark[_ngcontent-%COMP%]{width:4.4rem;height:4.4rem;border:1px solid var(--platform-line);border-radius:1.2rem;background:radial-gradient(circle at 50% 34%,rgba(59,130,246,.34),transparent 60%),linear-gradient(180deg,color-mix(in srgb,var(--platform-panel-strong) 96%,transparent),color-mix(in srgb,var(--platform-panel) 94%,transparent));color:var(--platform-text);box-shadow:inset 0 1px color-mix(in srgb,var(--platform-text) 12%,transparent);font-size:1.8rem}.apns-hero__copy[_ngcontent-%COMP%]   span[_ngcontent-%COMP%]{display:block}.apns-hero__copy[_ngcontent-%COMP%]   h1[_ngcontent-%COMP%]{margin:.22rem 0 0;max-width:52rem;font-size:clamp(1.7rem,4vw,2.65rem);font-weight:820}@media(max-width:720px){.apns-hero[_ngcontent-%COMP%]{grid-template-columns:1fr}}.apns-option[_ngcontent-%COMP%], .apns-secret-row[_ngcontent-%COMP%], .apns-resource-card[_ngcontent-%COMP%], .apns-capability-row[_ngcontent-%COMP%]{border:0;border-radius:1.15rem;background:color-mix(in srgb,var(--platform-panel-strong) 78%,transparent);box-shadow:inset 0 1px color-mix(in srgb,var(--platform-text) 7%,transparent),
30 16px 34px color-mix(in srgb,#3b82f6 7%,transparent)}.apns-option[_ngcontent-%COMP%]:hover, .apns-resource-card[_ngcontent-%COMP%]:hover, .apns-option--active[_ngcontent-%COMP%]{background:linear-gradient(135deg,color-mix(in srgb,#3b82f6 24%,var(--platform-panel-strong)),color-mix(in srgb,#3b82f6 10%,var(--platform-panel)));box-shadow:inset 0 1px color-mix(in srgb,white 16%,transparent),0 18px 42px color-mix(in srgb,#3b82f6 16%,transparent)}.apns-accordion[_ngcontent-%COMP%]{display:block}.apns-accordion__summary[_ngcontent-%COMP%]{display:flex;align-items:center;justify-content:space-between;gap:1rem;min-height:3rem;color:var(--platform-text);cursor:pointer;list-style:none}.apns-accordion__summary[_ngcontent-%COMP%]::-webkit-details-marker{display:none}.apns-accordion__summary[_ngcontent-%COMP%]   span[_ngcontent-%COMP%]{font-size:1rem;font-weight:820;letter-spacing:-.03em}.apns-accordion__summary[_ngcontent-%COMP%]   i[_ngcontent-%COMP%]{transition:transform .18s ease}.apns-accordion[open][_ngcontent-%COMP%]   .apns-accordion__summary[_ngcontent-%COMP%]   i[_ngcontent-%COMP%]{transform:rotate(180deg)}.apns-accordion__content[_ngcontent-%COMP%], .apns-accordion__prompt-header[_ngcontent-%COMP%]{margin-top:1rem}.apns-accordion-card[_ngcontent-%COMP%]{display:grid;align-content:start;border-radius:1rem;background:color-mix(in srgb,var(--platform-panel-strong) 78%,transparent);padding:1rem;box-shadow:inset 0 1px color-mix(in srgb,var(--platform-text) 7%,transparent),0 16px 34px color-mix(in srgb,#3b82f6 7%,transparent)}.apns-accordion__prompt-header[_ngcontent-%COMP%]{display:flex;justify-content:space-between;gap:1rem;align-items:center}@media(max-width:820px){.apns-accordion__prompt-header[_ngcontent-%COMP%]{align-items:stretch;flex-direction:column}}"]})}};export{K as ApnsNotificationsPageComponent};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.