@sitepong/fastnode 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/actions/index.cjs +27 -6
  2. package/dist/actions/index.cjs.map +1 -1
  3. package/dist/actions/index.mjs +27 -6
  4. package/dist/actions/index.mjs.map +1 -1
  5. package/dist/cert/index.d.cts +3 -3
  6. package/dist/cert/index.d.ts +3 -3
  7. package/dist/{cert-DtYDJBjG.d.ts → cert-e5GAgAPb.d.ts} +1 -1
  8. package/dist/{cert-6m1R8UeW.d.cts → cert-uLLdb5a7.d.cts} +1 -1
  9. package/dist/cli/index.cjs +27 -6
  10. package/dist/cli/index.cjs.map +1 -1
  11. package/dist/cli/index.d.cts +1 -1
  12. package/dist/cli/index.d.ts +1 -1
  13. package/dist/cli/index.mjs +27 -6
  14. package/dist/cli/index.mjs.map +1 -1
  15. package/dist/client/index.cjs +27 -6
  16. package/dist/client/index.cjs.map +1 -1
  17. package/dist/client/index.d.cts +1 -1
  18. package/dist/client/index.d.ts +1 -1
  19. package/dist/client/index.mjs +27 -6
  20. package/dist/client/index.mjs.map +1 -1
  21. package/dist/deliver/index.d.cts +2 -2
  22. package/dist/deliver/index.d.ts +2 -2
  23. package/dist/{index-Ce-WMV7c.d.cts → index-BN0iWhuw.d.cts} +1 -1
  24. package/dist/{index-CQKpbHZt.d.ts → index-BNP7Bpu5.d.ts} +1 -1
  25. package/dist/{index-CsFIp7OO.d.ts → index-BbY_H_f6.d.ts} +1 -1
  26. package/dist/{index-AD8QXY1T.d.cts → index-BgHagzj1.d.cts} +1 -1
  27. package/dist/{index-KCB2q1-8.d.cts → index-BjkOUQcQ.d.cts} +1 -1
  28. package/dist/{index-D2z7RiAM.d.ts → index-BwwpAlk2.d.ts} +5 -0
  29. package/dist/{index-Kq3rbG0u.d.ts → index-C2YLoFVl.d.ts} +1 -1
  30. package/dist/{index-CojSGJ7m.d.ts → index-CEldrbyz.d.ts} +1 -1
  31. package/dist/{index-CMH_GpN9.d.cts → index-CdfgEZwh.d.cts} +5 -0
  32. package/dist/{index-BW8wQUGC.d.cts → index-Clyf4-lu.d.cts} +1 -1
  33. package/dist/{index-CCs5irG7.d.cts → index-CtydPNxA.d.cts} +1 -1
  34. package/dist/{index-CQd4bo3G.d.cts → index-DHxi-QPC.d.cts} +3 -3
  35. package/dist/{index-DZaPkUnC.d.ts → index-Di4Ic0EE.d.ts} +3 -3
  36. package/dist/{index-BWK-T2-S.d.cts → index-DrCOh0Vh.d.cts} +1 -1
  37. package/dist/{index-BpiEBPVd.d.ts → index-EKU_G1G5.d.ts} +1 -1
  38. package/dist/{index-CdYdwxpQ.d.cts → index-XsMsVc3O.d.cts} +1 -1
  39. package/dist/{index-CLsvyTkh.d.ts → index-jeI44Q5G.d.ts} +1 -1
  40. package/dist/{index-D82CmjMP.d.ts → index-mddpvrRX.d.ts} +1 -1
  41. package/dist/index.cjs +148 -9
  42. package/dist/index.cjs.map +1 -1
  43. package/dist/index.d.cts +40 -13
  44. package/dist/index.d.ts +40 -13
  45. package/dist/index.mjs +148 -9
  46. package/dist/index.mjs.map +1 -1
  47. package/dist/lane/index.cjs +27 -6
  48. package/dist/lane/index.cjs.map +1 -1
  49. package/dist/lane/index.mjs +27 -6
  50. package/dist/lane/index.mjs.map +1 -1
  51. package/dist/match/index.d.cts +4 -4
  52. package/dist/match/index.d.ts +4 -4
  53. package/dist/pem/index.d.cts +2 -2
  54. package/dist/pem/index.d.ts +2 -2
  55. package/dist/pilot/index.d.cts +2 -2
  56. package/dist/pilot/index.d.ts +2 -2
  57. package/dist/precheck/index.d.cts +2 -2
  58. package/dist/precheck/index.d.ts +2 -2
  59. package/dist/produce/index.d.cts +2 -2
  60. package/dist/produce/index.d.ts +2 -2
  61. package/dist/sigh/index.d.cts +2 -2
  62. package/dist/sigh/index.d.ts +2 -2
  63. package/package.json +1 -1
package/dist/index.d.cts CHANGED
@@ -1,18 +1,18 @@
1
- import { A as AppleSession } from './index-CMH_GpN9.cjs';
2
- export { j as App, K as AppScreenshot, M as AppScreenshotSet, I as AppScreenshotsResource, a as AppStoreConnectClient, d as AppStoreConnectConfig, b as AppStoreConnectError, G as AppStoreVersion, H as AppStoreVersionLocalization, Q as AppStoreVersionSubmission, F as AppStoreVersionsResource, x as AppsResource, m as BetaBuildLocalization, l as BetaGroup, z as BetaGroupsResource, k as Build, n as BuildBetaDetail, y as BuildsResource, B as BundleId, p as BundleIdCapability, v as BundleIdsResource, E as CapabilitiesResource, s as CapabilityOption, r as CapabilitySetting, q as CapabilitySettingInput, C as Certificate, t as CertificatesResource, D as Device, w as DevicesResource, i as JsonApiError, h as JsonApiListResponse, J as JsonApiResource, g as JsonApiResponse, L as ListParams, o as PreReleaseVersion, P as Profile, u as ProfilesResource, c as RateLimitError, R as RequestClient, f as RequestOptions, O as ReviewSubmission, N as ReviewSubmissionsResource, e as TokenConfig, T as TokenManager, U as UploadOperation } from './index-CMH_GpN9.cjs';
1
+ import { A as AppleSession } from './index-CdfgEZwh.cjs';
2
+ export { j as App, K as AppScreenshot, M as AppScreenshotSet, I as AppScreenshotsResource, a as AppStoreConnectClient, d as AppStoreConnectConfig, b as AppStoreConnectError, G as AppStoreVersion, H as AppStoreVersionLocalization, Q as AppStoreVersionSubmission, F as AppStoreVersionsResource, x as AppsResource, m as BetaBuildLocalization, l as BetaGroup, z as BetaGroupsResource, k as Build, n as BuildBetaDetail, y as BuildsResource, B as BundleId, p as BundleIdCapability, v as BundleIdsResource, E as CapabilitiesResource, s as CapabilityOption, r as CapabilitySetting, q as CapabilitySettingInput, C as Certificate, t as CertificatesResource, D as Device, w as DevicesResource, i as JsonApiError, h as JsonApiListResponse, J as JsonApiResource, g as JsonApiResponse, L as ListParams, o as PreReleaseVersion, P as Profile, u as ProfilesResource, c as RateLimitError, R as RequestClient, f as RequestOptions, O as ReviewSubmission, N as ReviewSubmissionsResource, e as TokenConfig, T as TokenManager, U as UploadOperation } from './index-CdfgEZwh.cjs';
3
3
  export { A as AppStoreVersionState, i as BetaReviewState, h as BuildProcessingState, B as BundleIdPlatform, f as CapabilityOptionKey, e as CapabilitySettingsKey, d as CapabilityType, C as CertificateType, g as ContentRightsDeclaration, D as DeviceClass, c as DeviceStatus, E as ExportMethod, b as Platform, a as ProfileState, P as ProfileType, R as ReleaseType } from './enums-B609j2rb.cjs';
4
- export { i as cert } from './index-CCs5irG7.cjs';
5
- export { i as sigh } from './index-Ce-WMV7c.cjs';
6
- export { i as match } from './index-CQd4bo3G.cjs';
7
- export { i as produce } from './index-KCB2q1-8.cjs';
8
- export { i as pilot } from './index-AD8QXY1T.cjs';
9
- export { i as deliver } from './index-CdYdwxpQ.cjs';
10
- export { i as pem } from './index-BWK-T2-S.cjs';
4
+ export { i as cert } from './index-CtydPNxA.cjs';
5
+ export { i as sigh } from './index-BN0iWhuw.cjs';
6
+ export { i as match } from './index-DHxi-QPC.cjs';
7
+ export { i as produce } from './index-BjkOUQcQ.cjs';
8
+ export { i as pilot } from './index-BgHagzj1.cjs';
9
+ export { i as deliver } from './index-XsMsVc3O.cjs';
10
+ export { i as pem } from './index-DrCOh0Vh.cjs';
11
11
  export { i as gym } from './index-DrUpRXRG.cjs';
12
12
  export { i as scan } from './index-BimqCmY8.cjs';
13
13
  export { i as snapshot } from './index-CR3BFPIz.cjs';
14
14
  export { i as trainer } from './index-BoU8qt8r.cjs';
15
- export { i as precheck } from './index-BW8wQUGC.cjs';
15
+ export { i as precheck } from './index-Clyf4-lu.cjs';
16
16
  export { i as frameit } from './index-BYonklf3.cjs';
17
17
  export { i as xcode } from './index-Cp6cjtd-.cjs';
18
18
  export { i as core } from './index-C2yG3wXA.cjs';
@@ -20,7 +20,7 @@ export { LaneCallback, LaneDefinition, RunLaneOptions, RunResult, afterAll, afte
20
20
  export { L as LaneContext } from './context-CymLkfrS.cjs';
21
21
  export { ActionDefinition, action, ensureActionsRegistered, getAction, listActions, registerAction } from './actions/index.cjs';
22
22
  export { createCli } from './cli/index.cjs';
23
- import './cert-6m1R8UeW.cjs';
23
+ import './cert-uLLdb5a7.cjs';
24
24
  import 'commander';
25
25
 
26
26
  /**
@@ -68,6 +68,16 @@ interface OneClickInventory {
68
68
  used: number;
69
69
  max: number;
70
70
  };
71
+ /** Active APNs Authentication Keys. Apple caps a team at 2. */
72
+ apnsAuthKeys: {
73
+ keyId: string;
74
+ keyName: string;
75
+ dateCreated?: string;
76
+ }[];
77
+ apnsKeyCapacity: {
78
+ used: number;
79
+ max: number;
80
+ };
71
81
  pushCerts: {
72
82
  certificateId: string;
73
83
  name: string;
@@ -98,20 +108,37 @@ interface OneClickOptions {
98
108
  /**
99
109
  * Generate an APNs Authentication Key (.p8) for push notifications.
100
110
  * Default true. ONE key per team works for ALL apps and never expires.
101
- * Created via the developer portal's `account/auth/key/v2/create`
102
- * endpoint, downloaded immediately via `account/auth/key/download`.
111
+ * The modern replacement for the legacy per-app .p12 push certs.
103
112
  *
104
113
  * Apple allows multiple APNs keys per team — the wizard always
105
114
  * creates a new one when this flag is set, regardless of what's
106
115
  * already in the team. Unrelated existing keys are not affected.
107
116
  */
108
117
  generateApnsAuthKey?: boolean;
118
+ /**
119
+ * Generate an APNs **Production** push certificate (.p12). Default
120
+ * false — the modern APNs Auth Key (.p8) above replaces this and is
121
+ * generally preferred. Only enable if a downstream integration
122
+ * specifically requires the legacy cert-based APNs path.
123
+ *
124
+ * Apple caps these at 1 per bundle per environment, so existing
125
+ * production push certs for the bundle are left alone (the wizard
126
+ * skips with a warning rather than revoking).
127
+ */
128
+ generatePushProductionCert?: boolean;
129
+ /**
130
+ * Generate an APNs **Sandbox** (development) push certificate (.p12).
131
+ * Default false. Same caveats as `generatePushProductionCert`.
132
+ */
133
+ generatePushSandboxCert?: boolean;
109
134
  /** Enable Sign in with Apple capability on the bundle ID. Default true. */
110
135
  enableSignInWithApple?: boolean;
111
136
  /** Enable Push Notifications capability on the bundle ID. Default true. */
112
137
  enablePushNotifications?: boolean;
113
138
  /** Distribution cert IDs to revoke before creating the new one (for the 3-cert limit). */
114
139
  revokeCertIds?: string[];
140
+ /** APNs auth key IDs to revoke before creating the new one (Apple caps APNs keys at 2/team). */
141
+ revokeApnsKeyIds?: string[];
115
142
  }
116
143
  interface OneClickInput {
117
144
  session: AppleSession;
package/dist/index.d.ts CHANGED
@@ -1,18 +1,18 @@
1
- import { A as AppleSession } from './index-D2z7RiAM.js';
2
- export { j as App, K as AppScreenshot, M as AppScreenshotSet, I as AppScreenshotsResource, a as AppStoreConnectClient, d as AppStoreConnectConfig, b as AppStoreConnectError, G as AppStoreVersion, H as AppStoreVersionLocalization, Q as AppStoreVersionSubmission, F as AppStoreVersionsResource, x as AppsResource, m as BetaBuildLocalization, l as BetaGroup, z as BetaGroupsResource, k as Build, n as BuildBetaDetail, y as BuildsResource, B as BundleId, p as BundleIdCapability, v as BundleIdsResource, E as CapabilitiesResource, s as CapabilityOption, r as CapabilitySetting, q as CapabilitySettingInput, C as Certificate, t as CertificatesResource, D as Device, w as DevicesResource, i as JsonApiError, h as JsonApiListResponse, J as JsonApiResource, g as JsonApiResponse, L as ListParams, o as PreReleaseVersion, P as Profile, u as ProfilesResource, c as RateLimitError, R as RequestClient, f as RequestOptions, O as ReviewSubmission, N as ReviewSubmissionsResource, e as TokenConfig, T as TokenManager, U as UploadOperation } from './index-D2z7RiAM.js';
1
+ import { A as AppleSession } from './index-BwwpAlk2.js';
2
+ export { j as App, K as AppScreenshot, M as AppScreenshotSet, I as AppScreenshotsResource, a as AppStoreConnectClient, d as AppStoreConnectConfig, b as AppStoreConnectError, G as AppStoreVersion, H as AppStoreVersionLocalization, Q as AppStoreVersionSubmission, F as AppStoreVersionsResource, x as AppsResource, m as BetaBuildLocalization, l as BetaGroup, z as BetaGroupsResource, k as Build, n as BuildBetaDetail, y as BuildsResource, B as BundleId, p as BundleIdCapability, v as BundleIdsResource, E as CapabilitiesResource, s as CapabilityOption, r as CapabilitySetting, q as CapabilitySettingInput, C as Certificate, t as CertificatesResource, D as Device, w as DevicesResource, i as JsonApiError, h as JsonApiListResponse, J as JsonApiResource, g as JsonApiResponse, L as ListParams, o as PreReleaseVersion, P as Profile, u as ProfilesResource, c as RateLimitError, R as RequestClient, f as RequestOptions, O as ReviewSubmission, N as ReviewSubmissionsResource, e as TokenConfig, T as TokenManager, U as UploadOperation } from './index-BwwpAlk2.js';
3
3
  export { A as AppStoreVersionState, i as BetaReviewState, h as BuildProcessingState, B as BundleIdPlatform, f as CapabilityOptionKey, e as CapabilitySettingsKey, d as CapabilityType, C as CertificateType, g as ContentRightsDeclaration, D as DeviceClass, c as DeviceStatus, E as ExportMethod, b as Platform, a as ProfileState, P as ProfileType, R as ReleaseType } from './enums-B609j2rb.js';
4
- export { i as cert } from './index-CQKpbHZt.js';
5
- export { i as sigh } from './index-CojSGJ7m.js';
6
- export { i as match } from './index-DZaPkUnC.js';
7
- export { i as produce } from './index-BpiEBPVd.js';
8
- export { i as pilot } from './index-D82CmjMP.js';
9
- export { i as deliver } from './index-CsFIp7OO.js';
10
- export { i as pem } from './index-Kq3rbG0u.js';
4
+ export { i as cert } from './index-BNP7Bpu5.js';
5
+ export { i as sigh } from './index-CEldrbyz.js';
6
+ export { i as match } from './index-Di4Ic0EE.js';
7
+ export { i as produce } from './index-EKU_G1G5.js';
8
+ export { i as pilot } from './index-mddpvrRX.js';
9
+ export { i as deliver } from './index-BbY_H_f6.js';
10
+ export { i as pem } from './index-C2YLoFVl.js';
11
11
  export { i as gym } from './index-DImN9PWc.js';
12
12
  export { i as scan } from './index-BimqCmY8.js';
13
13
  export { i as snapshot } from './index-CR3BFPIz.js';
14
14
  export { i as trainer } from './index-BoU8qt8r.js';
15
- export { i as precheck } from './index-CLsvyTkh.js';
15
+ export { i as precheck } from './index-jeI44Q5G.js';
16
16
  export { i as frameit } from './index-BYonklf3.js';
17
17
  export { i as xcode } from './index-Cp6cjtd-.js';
18
18
  export { i as core } from './index-C2yG3wXA.js';
@@ -20,7 +20,7 @@ export { LaneCallback, LaneDefinition, RunLaneOptions, RunResult, afterAll, afte
20
20
  export { L as LaneContext } from './context-CymLkfrS.js';
21
21
  export { ActionDefinition, action, ensureActionsRegistered, getAction, listActions, registerAction } from './actions/index.js';
22
22
  export { createCli } from './cli/index.js';
23
- import './cert-DtYDJBjG.js';
23
+ import './cert-e5GAgAPb.js';
24
24
  import 'commander';
25
25
 
26
26
  /**
@@ -68,6 +68,16 @@ interface OneClickInventory {
68
68
  used: number;
69
69
  max: number;
70
70
  };
71
+ /** Active APNs Authentication Keys. Apple caps a team at 2. */
72
+ apnsAuthKeys: {
73
+ keyId: string;
74
+ keyName: string;
75
+ dateCreated?: string;
76
+ }[];
77
+ apnsKeyCapacity: {
78
+ used: number;
79
+ max: number;
80
+ };
71
81
  pushCerts: {
72
82
  certificateId: string;
73
83
  name: string;
@@ -98,20 +108,37 @@ interface OneClickOptions {
98
108
  /**
99
109
  * Generate an APNs Authentication Key (.p8) for push notifications.
100
110
  * Default true. ONE key per team works for ALL apps and never expires.
101
- * Created via the developer portal's `account/auth/key/v2/create`
102
- * endpoint, downloaded immediately via `account/auth/key/download`.
111
+ * The modern replacement for the legacy per-app .p12 push certs.
103
112
  *
104
113
  * Apple allows multiple APNs keys per team — the wizard always
105
114
  * creates a new one when this flag is set, regardless of what's
106
115
  * already in the team. Unrelated existing keys are not affected.
107
116
  */
108
117
  generateApnsAuthKey?: boolean;
118
+ /**
119
+ * Generate an APNs **Production** push certificate (.p12). Default
120
+ * false — the modern APNs Auth Key (.p8) above replaces this and is
121
+ * generally preferred. Only enable if a downstream integration
122
+ * specifically requires the legacy cert-based APNs path.
123
+ *
124
+ * Apple caps these at 1 per bundle per environment, so existing
125
+ * production push certs for the bundle are left alone (the wizard
126
+ * skips with a warning rather than revoking).
127
+ */
128
+ generatePushProductionCert?: boolean;
129
+ /**
130
+ * Generate an APNs **Sandbox** (development) push certificate (.p12).
131
+ * Default false. Same caveats as `generatePushProductionCert`.
132
+ */
133
+ generatePushSandboxCert?: boolean;
109
134
  /** Enable Sign in with Apple capability on the bundle ID. Default true. */
110
135
  enableSignInWithApple?: boolean;
111
136
  /** Enable Push Notifications capability on the bundle ID. Default true. */
112
137
  enablePushNotifications?: boolean;
113
138
  /** Distribution cert IDs to revoke before creating the new one (for the 3-cert limit). */
114
139
  revokeCertIds?: string[];
140
+ /** APNs auth key IDs to revoke before creating the new one (Apple caps APNs keys at 2/team). */
141
+ revokeApnsKeyIds?: string[];
115
142
  }
116
143
  interface OneClickInput {
117
144
  session: AppleSession;
package/dist/index.mjs CHANGED
@@ -2476,6 +2476,12 @@ var init_xcode_metrics = __esm({
2476
2476
  });
2477
2477
 
2478
2478
  // src/client/portal.ts
2479
+ function pickUniqueKeyName(base, taken) {
2480
+ if (!taken.has(base)) return base;
2481
+ let n = 1;
2482
+ while (taken.has(`${base} - ${n}`)) n++;
2483
+ return `${base} - ${n}`;
2484
+ }
2479
2485
  var PORTAL_BASE, PortalClient;
2480
2486
  var init_portal = __esm({
2481
2487
  "src/client/portal.ts"() {
@@ -2594,12 +2600,17 @@ var init_portal = __esm({
2594
2600
  * + period and collapse whitespace.
2595
2601
  */
2596
2602
  async createApiKey(rawName, serviceConfigurations = {}) {
2597
- const name = rawName.replace(/[^A-Za-z0-9 _\-.]/g, " ").replace(/\s+/g, " ").trim().slice(0, 50);
2598
- if (!name) throw new Error("createApiKey: name is empty after sanitization");
2603
+ const baseName = rawName.replace(/[^A-Za-z0-9 _\-.]/g, " ").replace(/\s+/g, " ").trim().slice(0, 45);
2604
+ if (!baseName) throw new Error("createApiKey: name is empty after sanitization");
2605
+ let existingNames = /* @__PURE__ */ new Set();
2599
2606
  try {
2600
- await this.listApiKeys();
2607
+ const list = await this.listApiKeys();
2608
+ existingNames = new Set(
2609
+ (list.keys ?? []).map((k) => String(k.keyName ?? "").trim())
2610
+ );
2601
2611
  } catch {
2602
2612
  }
2613
+ const name = pickUniqueKeyName(baseName, existingNames);
2603
2614
  const body = {
2604
2615
  teamId: this.teamId,
2605
2616
  name,
@@ -2654,14 +2665,24 @@ var init_portal = __esm({
2654
2665
  * The exact body comes from @expo/apple-utils v2.1.21 — both fields
2655
2666
  * are produced by separate functions (`d` for the map, `h` for the
2656
2667
  * array) and merged into the create payload.
2668
+ *
2669
+ * Apple also rejects duplicate key names ("Another key with same
2670
+ * name exists") — we dedupe by listing existing keys first and
2671
+ * appending " (N)" until we find a free slot, mirroring the
2672
+ * provisioning profile dedup.
2657
2673
  */
2658
2674
  async createApnsAuthKey(rawName) {
2659
- const name = rawName.replace(/[^A-Za-z0-9 _\-.]/g, " ").replace(/\s+/g, " ").trim().slice(0, 50);
2660
- if (!name) throw new Error("createApnsAuthKey: name is empty after sanitization");
2675
+ const baseName = rawName.replace(/[^A-Za-z0-9 _\-.]/g, " ").replace(/\s+/g, " ").trim().slice(0, 45);
2676
+ if (!baseName) throw new Error("createApnsAuthKey: name is empty after sanitization");
2677
+ let existingNames = /* @__PURE__ */ new Set();
2661
2678
  try {
2662
- await this.listApiKeys();
2679
+ const list = await this.listApiKeys();
2680
+ existingNames = new Set(
2681
+ (list.keys ?? []).map((k) => String(k.keyName ?? "").trim())
2682
+ );
2663
2683
  } catch {
2664
2684
  }
2685
+ const name = pickUniqueKeyName(baseName, existingNames);
2665
2686
  const body = {
2666
2687
  teamId: this.teamId,
2667
2688
  name,
@@ -8977,6 +8998,8 @@ init_iris();
8977
8998
  init_client();
8978
8999
  init_csr();
8979
9000
  var DIST_CERT_TYPE = PortalClient.CERT_TYPES.IOS_DISTRIBUTION;
9001
+ var PUSH_PROD_TYPE = PortalClient.CERT_TYPES.IOS_PRODUCTION_PUSH;
9002
+ var PUSH_DEV_TYPE = PortalClient.CERT_TYPES.IOS_DEVELOPMENT_PUSH;
8980
9003
  function randomPassword(length = 32) {
8981
9004
  const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
8982
9005
  const bytes = randomBytes(length);
@@ -9023,11 +9046,12 @@ async function oneClickListTeams(session) {
9023
9046
  async function oneClickInventory(session, teamId) {
9024
9047
  const portal = new PortalClient(session, teamId);
9025
9048
  await portal.init();
9026
- const [appIds, allCerts, profiles, pushCerts] = await Promise.all([
9049
+ const [appIds, allCerts, profiles, pushCerts, apiKeys] = await Promise.all([
9027
9050
  portal.listAppIds(),
9028
9051
  portal.listCertificates([DIST_CERT_TYPE]),
9029
9052
  portal.listProfiles(),
9030
- portal.listPushCertificates()
9053
+ portal.listPushCertificates(),
9054
+ portal.listApiKeys().catch(() => ({ keys: [] }))
9031
9055
  ]);
9032
9056
  const distributionCerts = (allCerts ?? []).map((c) => ({
9033
9057
  certificateId: c.certificateId,
@@ -9036,6 +9060,15 @@ async function oneClickInventory(session, teamId) {
9036
9060
  expirationDate: c.expirationDateString,
9037
9061
  ownerName: c.ownerName
9038
9062
  }));
9063
+ const apnsAuthKeys = (apiKeys.keys ?? []).filter(
9064
+ (k) => (k.services ?? []).some(
9065
+ (s) => s.id === PortalClient.APNS_SERVICE_ID || /apns/i.test(s.name ?? "")
9066
+ )
9067
+ ).map((k) => ({
9068
+ keyId: k.keyId,
9069
+ keyName: k.keyName,
9070
+ dateCreated: k.dateCreated
9071
+ }));
9039
9072
  return {
9040
9073
  team: { id: teamId },
9041
9074
  bundleIds: (appIds ?? []).map((a) => ({
@@ -9045,6 +9078,8 @@ async function oneClickInventory(session, teamId) {
9045
9078
  })),
9046
9079
  distributionCerts,
9047
9080
  distCertCapacity: { used: distributionCerts.length, max: 3 },
9081
+ apnsAuthKeys,
9082
+ apnsKeyCapacity: { used: apnsAuthKeys.length, max: 2 },
9048
9083
  pushCerts: (pushCerts ?? []).map((c) => ({
9049
9084
  certificateId: c.certificateId,
9050
9085
  name: c.name ?? "Push",
@@ -9082,15 +9117,52 @@ async function createDistCert(portal) {
9082
9117
  }
9083
9118
  return { certificateId: cert.certificateId, privateKeyPem: privateKey, certContent };
9084
9119
  }
9120
+ async function createPushCert(portal, appIdId, type) {
9121
+ const { csr, privateKey } = generateRSACSR();
9122
+ const cert = await portal.createCertificate({ type, csrContent: csr, appIdId });
9123
+ let certContent;
9124
+ if (cert.certificateContent) {
9125
+ certContent = Buffer.from(cert.certificateContent, "base64");
9126
+ } else {
9127
+ certContent = await portal.downloadCertificate(cert.certificateId, type);
9128
+ }
9129
+ return { certificateId: cert.certificateId, privateKeyPem: privateKey, certContent };
9130
+ }
9131
+ function findExistingPushCertForBundle(pushCerts, appIdId, bundleIdentifier, kind) {
9132
+ for (const c of pushCerts) {
9133
+ const appMatches = c.appId?.appIdId === appIdId || c.appId?.identifier === bundleIdentifier;
9134
+ if (!appMatches) continue;
9135
+ const ts = (c.typeString ?? "").toLowerCase();
9136
+ const name = (c.name ?? "").toLowerCase();
9137
+ const looksLikePush = ts.includes("push") || ts.includes("apns") || name.includes("apple push services");
9138
+ if (!looksLikePush) continue;
9139
+ const isProduction = ts.includes("production");
9140
+ const isSandbox = ts.includes("development") || ts.includes("sandbox");
9141
+ const isUnified = !isProduction && !isSandbox;
9142
+ if (!isUnified) {
9143
+ if (kind === "production" && !isProduction) continue;
9144
+ if (kind === "sandbox" && !isSandbox) continue;
9145
+ }
9146
+ return {
9147
+ certificateId: c.certificateId,
9148
+ name: c.name ?? "Apple Push Services",
9149
+ expirationDate: c.expirationDateString
9150
+ };
9151
+ }
9152
+ return null;
9153
+ }
9085
9154
  async function oneClickSetup(input) {
9086
9155
  const opts = {
9087
9156
  generateDistributionCert: input.options?.generateDistributionCert ?? true,
9088
9157
  generateStoreProfile: input.options?.generateStoreProfile ?? true,
9089
9158
  generateAscApiKey: input.options?.generateAscApiKey ?? true,
9090
9159
  generateApnsAuthKey: input.options?.generateApnsAuthKey ?? true,
9160
+ generatePushProductionCert: input.options?.generatePushProductionCert ?? false,
9161
+ generatePushSandboxCert: input.options?.generatePushSandboxCert ?? false,
9091
9162
  enableSignInWithApple: input.options?.enableSignInWithApple ?? true,
9092
9163
  enablePushNotifications: input.options?.enablePushNotifications ?? true,
9093
- revokeCertIds: input.options?.revokeCertIds ?? []
9164
+ revokeCertIds: input.options?.revokeCertIds ?? [],
9165
+ revokeApnsKeyIds: input.options?.revokeApnsKeyIds ?? []
9094
9166
  };
9095
9167
  const onProgress = input.onProgress ?? (() => {
9096
9168
  });
@@ -9161,6 +9233,11 @@ async function oneClickSetup(input) {
9161
9233
  created.provisioningProfileId = profile.id;
9162
9234
  const profileMeta = extractProfileMetadata(profile.content);
9163
9235
  if (profileMeta.uuid) created.profileUuid = profileMeta.uuid;
9236
+ for (const keyId of opts.revokeApnsKeyIds) {
9237
+ await step(`revoke_apns:${keyId}`, `Revoke APNs auth key ${keyId}`, async () => {
9238
+ await portal.revokeApiKey(keyId);
9239
+ });
9240
+ }
9164
9241
  if (opts.generateApnsAuthKey) {
9165
9242
  await step("apns_auth_key", "APNs Authentication Key (.p8)", async () => {
9166
9243
  try {
@@ -9178,6 +9255,68 @@ async function oneClickSetup(input) {
9178
9255
  }
9179
9256
  });
9180
9257
  }
9258
+ let pushCertCache = null;
9259
+ const loadPushCerts = async () => {
9260
+ if (pushCertCache == null) {
9261
+ pushCertCache = await portal.listPushCertificates();
9262
+ }
9263
+ return pushCertCache;
9264
+ };
9265
+ async function provisionLegacyPushCert(stepId, label, kind, pushType, certType, friendlyName) {
9266
+ await step(stepId, label, async () => {
9267
+ try {
9268
+ const existing = findExistingPushCertForBundle(
9269
+ await loadPushCerts(),
9270
+ appIdId,
9271
+ input.bundleIdentifier,
9272
+ kind
9273
+ );
9274
+ if (existing) {
9275
+ warnings.push(
9276
+ `${label} already exists for ${input.bundleIdentifier} ("${existing.name}"` + (existing.expirationDate ? `, expires ${existing.expirationDate}` : "") + `). Skipped \u2014 Apple caps these at 1 per bundle per environment and we can't recover the existing private key. Revoke it manually in Apple Developer Portal and re-run if you need a sitepong-managed copy.`
9277
+ );
9278
+ return;
9279
+ }
9280
+ const c = await createPushCert(portal, appIdId, pushType);
9281
+ const pushPassword = randomPassword();
9282
+ const p12 = bundleP12({
9283
+ certificate: c.certContent,
9284
+ privateKeyPem: c.privateKeyPem,
9285
+ password: pushPassword,
9286
+ friendlyName
9287
+ });
9288
+ additionalCerts.push({
9289
+ cert_type: certType,
9290
+ cert_base64: p12.toString("base64"),
9291
+ cert_password: pushPassword
9292
+ });
9293
+ } catch (err) {
9294
+ warnings.push(
9295
+ `${label} could not be created: ${err.message}. You can upload an existing .p12 manually from the credentials list.`
9296
+ );
9297
+ }
9298
+ });
9299
+ }
9300
+ if (opts.generatePushProductionCert) {
9301
+ await provisionLegacyPushCert(
9302
+ "push_prod_cert",
9303
+ "APS Production push certificate (.p12)",
9304
+ "production",
9305
+ PUSH_PROD_TYPE,
9306
+ "aps_production",
9307
+ `${input.appName} APNs Production`
9308
+ );
9309
+ }
9310
+ if (opts.generatePushSandboxCert) {
9311
+ await provisionLegacyPushCert(
9312
+ "push_sandbox_cert",
9313
+ "APS Sandbox push certificate (.p12)",
9314
+ "sandbox",
9315
+ PUSH_DEV_TYPE,
9316
+ "aps_sandbox",
9317
+ `${input.appName} APNs Sandbox`
9318
+ );
9319
+ }
9181
9320
  let ascKeyId = "";
9182
9321
  let ascIssuerId = "";
9183
9322
  let ascP8Base64 = "";