@sitepong/fastnode 0.3.1 → 0.3.2

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 (126) hide show
  1. package/dist/actions/index.cjs +1 -0
  2. package/dist/actions/index.cjs.map +1 -1
  3. package/dist/actions/index.mjs +1 -0
  4. package/dist/actions/index.mjs.map +1 -1
  5. package/dist/{apple-session-jUzBrql5.d.cts → apple-session-D6x7Jo3D.d.cts} +1 -1
  6. package/dist/{apple-session-jUzBrql5.d.ts → apple-session-D6x7Jo3D.d.ts} +1 -1
  7. package/dist/cert/index.cjs +92 -51
  8. package/dist/cert/index.cjs.map +1 -1
  9. package/dist/cert/index.d.cts +5 -5
  10. package/dist/cert/index.d.ts +5 -5
  11. package/dist/cert/index.mjs +92 -51
  12. package/dist/cert/index.mjs.map +1 -1
  13. package/dist/{cert-ClacRx9y.d.ts → cert-C-yRB-sO.d.ts} +2 -2
  14. package/dist/{cert-DffLKURp.d.cts → cert-C4hhKH1n.d.cts} +2 -2
  15. package/dist/cli/index.cjs +40 -23
  16. package/dist/cli/index.cjs.map +1 -1
  17. package/dist/cli/index.d.cts +3 -3
  18. package/dist/cli/index.d.ts +3 -3
  19. package/dist/cli/index.mjs +40 -23
  20. package/dist/cli/index.mjs.map +1 -1
  21. package/dist/client/index.cjs +1 -0
  22. package/dist/client/index.cjs.map +1 -1
  23. package/dist/client/index.d.cts +3 -3
  24. package/dist/client/index.d.ts +3 -3
  25. package/dist/client/index.mjs +1 -0
  26. package/dist/client/index.mjs.map +1 -1
  27. package/dist/core/index.d.cts +1 -1
  28. package/dist/core/index.d.ts +1 -1
  29. package/dist/deliver/index.d.cts +4 -4
  30. package/dist/deliver/index.d.ts +4 -4
  31. package/dist/{enums-yXNVh3UI.d.cts → enums-BlpayMTx.d.cts} +1 -1
  32. package/dist/{enums-yXNVh3UI.d.ts → enums-BlpayMTx.d.ts} +1 -1
  33. package/dist/frameit/index.d.cts +1 -1
  34. package/dist/frameit/index.d.ts +1 -1
  35. package/dist/gradle/index.d.cts +1 -1
  36. package/dist/gradle/index.d.ts +1 -1
  37. package/dist/gym/index.d.cts +2 -2
  38. package/dist/gym/index.d.ts +2 -2
  39. package/dist/{index-DnHQ2uT2.d.cts → index-258t9n7v.d.cts} +2 -2
  40. package/dist/{index-Ol0RtbQA.d.ts → index-6LKy36sE.d.ts} +4 -4
  41. package/dist/{index-O3EMrd5s.d.cts → index-B74vgav6.d.cts} +4 -4
  42. package/dist/{index-BoU8qt8r.d.cts → index-B7ERdhh8.d.cts} +1 -1
  43. package/dist/{index-BoU8qt8r.d.ts → index-B7ERdhh8.d.ts} +1 -1
  44. package/dist/{index-CmcFPn_G.d.cts → index-BIRpj0f2.d.cts} +2 -2
  45. package/dist/{index-s2PigtDM.d.ts → index-BJLHWMwL.d.ts} +3 -3
  46. package/dist/{index-mEEB7An6.d.ts → index-B_D_01oz.d.ts} +1 -1
  47. package/dist/{index-C18cijCd.d.ts → index-Ba1jHQYg.d.ts} +1 -1
  48. package/dist/{index-925_Ov7X.d.cts → index-BawZaGqD.d.cts} +3 -3
  49. package/dist/{index-8djTPW8O.d.ts → index-BmrOdmNL.d.ts} +2 -2
  50. package/dist/{index-C-EEYXSE.d.ts → index-C8L03MBu.d.ts} +3 -3
  51. package/dist/{index-Cp6cjtd-.d.cts → index-CHLDQweM.d.cts} +1 -1
  52. package/dist/{index-Cp6cjtd-.d.ts → index-CHLDQweM.d.ts} +1 -1
  53. package/dist/{index-B6-MJpO4.d.cts → index-CRFfLsEG.d.cts} +1 -1
  54. package/dist/{index-N6eV5yym.d.ts → index-CV6KnSy1.d.ts} +2 -2
  55. package/dist/index-CX2hUvvG.d.cts +287 -0
  56. package/dist/index-CX2hUvvG.d.ts +287 -0
  57. package/dist/{index-Dkf5sH1E.d.ts → index-ClhWjR7a.d.ts} +2 -2
  58. package/dist/{index-BGhV0gS-.d.ts → index-Cq-xo-9x.d.ts} +2 -2
  59. package/dist/{index-CR3BFPIz.d.cts → index-Cw7ojUY5.d.cts} +1 -1
  60. package/dist/{index-CR3BFPIz.d.ts → index-Cw7ojUY5.d.ts} +1 -1
  61. package/dist/{index-C2yG3wXA.d.cts → index-CwD7lG0y.d.cts} +1 -1
  62. package/dist/{index-C2yG3wXA.d.ts → index-CwD7lG0y.d.ts} +1 -1
  63. package/dist/{index-_24DRp3a.d.cts → index-CxrqhkVF.d.cts} +1 -1
  64. package/dist/{index-on573dnO.d.cts → index-D3zyYCYs.d.cts} +2 -2
  65. package/dist/{index-BhGaVlK1.d.cts → index-DCrSWVMb.d.cts} +3 -3
  66. package/dist/{index-CBM5XZKC.d.ts → index-DP2f5ZsS.d.ts} +3 -3
  67. package/dist/{index-BbVQzSV1.d.cts → index-DRjXV9ej.d.cts} +3 -3
  68. package/dist/{index-Dv-Mek07.d.ts → index-DSXBQeur.d.cts} +1 -1
  69. package/dist/{index-Dv-Mek07.d.cts → index-DSXBQeur.d.ts} +1 -1
  70. package/dist/{index-BYonklf3.d.cts → index-Dvi-3DSM.d.cts} +1 -1
  71. package/dist/{index-BYonklf3.d.ts → index-Dvi-3DSM.d.ts} +1 -1
  72. package/dist/{index-D9YQQ3FM.d.ts → index-Dy8EWOnt.d.ts} +2 -2
  73. package/dist/{index-CpGV1f0L.d.cts → index-HWWl6HEL.d.cts} +3 -3
  74. package/dist/{index-isT08RuY.d.cts → index-QYgreJV3.d.cts} +2 -2
  75. package/dist/{index-CemR3UI9.d.ts → index-SyCMBpNN.d.ts} +3 -3
  76. package/dist/{index-DFstwgGK.d.cts → index-yro2MWgt.d.cts} +2 -2
  77. package/dist/index.cjs +1440 -948
  78. package/dist/index.cjs.map +1 -1
  79. package/dist/index.d.cts +23 -23
  80. package/dist/index.d.ts +23 -23
  81. package/dist/index.mjs +1441 -949
  82. package/dist/index.mjs.map +1 -1
  83. package/dist/lane/index.cjs +1 -0
  84. package/dist/lane/index.cjs.map +1 -1
  85. package/dist/lane/index.mjs +1 -0
  86. package/dist/lane/index.mjs.map +1 -1
  87. package/dist/match/index.d.cts +6 -6
  88. package/dist/match/index.d.ts +6 -6
  89. package/dist/match/index.mjs +1 -1
  90. package/dist/pem/index.d.cts +4 -4
  91. package/dist/pem/index.d.ts +4 -4
  92. package/dist/pilot/index.d.cts +4 -4
  93. package/dist/pilot/index.d.ts +4 -4
  94. package/dist/playstore/index.cjs +18208 -1
  95. package/dist/playstore/index.cjs.map +1 -1
  96. package/dist/playstore/index.d.cts +1 -1
  97. package/dist/playstore/index.d.ts +1 -1
  98. package/dist/playstore/index.mjs +18196 -2
  99. package/dist/playstore/index.mjs.map +1 -1
  100. package/dist/precheck/index.d.cts +4 -4
  101. package/dist/precheck/index.d.ts +4 -4
  102. package/dist/privacy/index.cjs +32 -22
  103. package/dist/privacy/index.cjs.map +1 -1
  104. package/dist/privacy/index.d.cts +2 -2
  105. package/dist/privacy/index.d.ts +2 -2
  106. package/dist/privacy/index.mjs +32 -22
  107. package/dist/privacy/index.mjs.map +1 -1
  108. package/dist/produce/index.d.cts +4 -4
  109. package/dist/produce/index.d.ts +4 -4
  110. package/dist/review/index.cjs +32 -22
  111. package/dist/review/index.cjs.map +1 -1
  112. package/dist/review/index.d.cts +2 -2
  113. package/dist/review/index.d.ts +2 -2
  114. package/dist/review/index.mjs +32 -22
  115. package/dist/review/index.mjs.map +1 -1
  116. package/dist/sigh/index.d.cts +4 -4
  117. package/dist/sigh/index.d.ts +4 -4
  118. package/dist/snapshot/index.d.cts +1 -1
  119. package/dist/snapshot/index.d.ts +1 -1
  120. package/dist/trainer/index.d.cts +1 -1
  121. package/dist/trainer/index.d.ts +1 -1
  122. package/dist/xcode/index.d.cts +1 -1
  123. package/dist/xcode/index.d.ts +1 -1
  124. package/package.json +2 -2
  125. package/dist/index-CXJlvmB4.d.cts +0 -63
  126. package/dist/index-CXJlvmB4.d.ts +0 -63
@@ -1,4 +1,4 @@
1
- import '../index-CpGV1f0L.cjs';
2
- export { A as ALL_RULES, P as PrecheckOptions, a as PrecheckRule, R as Rule, c as RuleResult, b as ValidationIssue, V as ValidationResult, v as validateMetadata } from '../index-on573dnO.cjs';
3
- import '../enums-yXNVh3UI.cjs';
4
- import '../apple-session-jUzBrql5.cjs';
1
+ import '../index-HWWl6HEL.cjs';
2
+ export { A as ALL_RULES, P as PrecheckOptions, a as PrecheckRule, R as Rule, b as RuleResult, V as ValidationIssue, c as ValidationResult, v as validateMetadata } from '../index-D3zyYCYs.cjs';
3
+ import '../enums-BlpayMTx.cjs';
4
+ import '../apple-session-D6x7Jo3D.cjs';
@@ -1,4 +1,4 @@
1
- import '../index-CemR3UI9.js';
2
- export { A as ALL_RULES, P as PrecheckOptions, a as PrecheckRule, R as Rule, c as RuleResult, b as ValidationIssue, V as ValidationResult, v as validateMetadata } from '../index-Dkf5sH1E.js';
3
- import '../enums-yXNVh3UI.js';
4
- import '../apple-session-jUzBrql5.js';
1
+ import '../index-SyCMBpNN.js';
2
+ export { A as ALL_RULES, P as PrecheckOptions, a as PrecheckRule, R as Rule, b as RuleResult, V as ValidationIssue, c as ValidationResult, v as validateMetadata } from '../index-ClhWjR7a.js';
3
+ import '../enums-BlpayMTx.js';
4
+ import '../apple-session-D6x7Jo3D.js';
@@ -1,8 +1,37 @@
1
1
  'use strict';
2
2
 
3
+ // src/client/providers.ts
4
+ var OLYMPUS_SESSION = "https://appstoreconnect.apple.com/olympus/v1/session";
5
+ function cookieHeader(session) {
6
+ return Object.entries(session.cookies).map(([k, v]) => `${k}=${v}`).join("; ");
7
+ }
8
+ function absorbCookies(session, res) {
9
+ for (const raw of res.headers.getSetCookie?.() ?? []) {
10
+ const m = raw.match(/^([^=]+)=([^;]*)/);
11
+ if (m) session.cookies[m[1]] = m[2];
12
+ }
13
+ }
14
+ async function listProviders(session) {
15
+ const res = await fetch(OLYMPUS_SESSION, { headers: { Cookie: cookieHeader(session), Accept: "application/json" } });
16
+ absorbCookies(session, res);
17
+ const info = await res.json().catch(() => null);
18
+ const pick = (p) => p?.providerId != null ? { providerId: Number(p.providerId), name: String(p.name ?? p.providerId) } : null;
19
+ const providers = (info?.availableProviders ?? []).map(pick).filter((p) => !!p);
20
+ return { current: pick(info?.provider), providers };
21
+ }
22
+ async function switchProvider(session, providerId) {
23
+ const res = await fetch(OLYMPUS_SESSION, {
24
+ method: "POST",
25
+ headers: { Cookie: cookieHeader(session), "Content-Type": "application/json", Accept: "application/json" },
26
+ body: JSON.stringify({ provider: { providerId } })
27
+ });
28
+ absorbCookies(session, res);
29
+ if (res.ok) session.teamId = String(providerId);
30
+ return res.ok;
31
+ }
32
+
3
33
  // src/privacy/index.ts
4
34
  var IRIS_BASE = "https://appstoreconnect.apple.com/iris/v1";
5
- var OLYMPUS_SESSION = "https://appstoreconnect.apple.com/olympus/v1/session";
6
35
  var DATA_USAGE_CATEGORIES = [
7
36
  "PAYMENT_INFORMATION",
8
37
  "CREDIT_AND_FRAUD",
@@ -71,15 +100,6 @@ async function iris(session, method, path, body) {
71
100
  }
72
101
  return { status: res.status, body: parsed, text };
73
102
  }
74
- function cookieHeader(session) {
75
- return Object.entries(session.cookies).map(([k, v]) => `${k}=${v}`).join("; ");
76
- }
77
- function absorbCookies(session, res) {
78
- for (const raw of res.headers.getSetCookie?.() ?? []) {
79
- const m = raw.match(/^([^=]+)=([^;]*)/);
80
- if (m) session.cookies[m[1]] = m[2];
81
- }
82
- }
83
103
  function fail(what, r) {
84
104
  const detail = r.body?.errors?.map((e) => e.detail ?? e.title).join("; ") || r.text.slice(0, 300);
85
105
  throw new Error(`${what} failed (HTTP ${r.status}): ${detail}`);
@@ -87,20 +107,10 @@ function fail(what, r) {
87
107
  async function selectProviderForApp(session, appId, onLog) {
88
108
  const owns = async () => (await iris(session, "GET", `/apps/${appId}?fields[apps]=name`)).status === 200;
89
109
  if (await owns()) return;
90
- const res = await fetch(OLYMPUS_SESSION, { headers: { Cookie: cookieHeader(session), Accept: "application/json" } });
91
- absorbCookies(session, res);
92
- const info = await res.json().catch(() => null);
93
- const providers = info?.availableProviders ?? [];
110
+ const { providers } = await listProviders(session);
94
111
  for (const p of providers) {
95
- const sw = await fetch(OLYMPUS_SESSION, {
96
- method: "POST",
97
- headers: { Cookie: cookieHeader(session), "Content-Type": "application/json", Accept: "application/json" },
98
- body: JSON.stringify({ provider: { providerId: p.providerId } })
99
- });
100
- absorbCookies(session, sw);
101
- if (sw.ok && await owns()) {
112
+ if (await switchProvider(session, p.providerId) && await owns()) {
102
113
  onLog?.(`Switched to team "${p.name}"`);
103
- session.teamId = String(p.providerId);
104
114
  return;
105
115
  }
106
116
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/privacy/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * App Privacy details (\"nutrition labels\") for an app in App Store Connect.\n * 1:1 port of Fastlane's `upload_app_privacy_details_to_app_store` action and\n * Spaceship's AppDataUsage / AppDataUsagesPublishState models.\n *\n * The public App Store Connect API has no endpoint for privacy details — an\n * API key cannot set them. Fastlane goes through the iris API that App Store\n * Connect's own web UI uses, authenticated with an Apple ID session, and so\n * does this: pass the AppleSession from `loginWithAppleId` / the App Release\n * sign-in.\n *\n * Usages use Fastlane's JSON format, so an existing `app_privacy_details.json`\n * works unchanged:\n *\n * [\n * { \"category\": \"EMAIL_ADDRESS\", \"purposes\": [\"APP_FUNCTIONALITY\"], \"data_protections\": [\"DATA_LINKED_TO_YOU\"] },\n * { \"data_protections\": [\"DATA_NOT_COLLECTED\"] } // an app that collects nothing\n * ]\n *\n * As in Fastlane, the upload REPLACES everything: existing usages are deleted\n * first, then the new ones are created, then the answers are published.\n */\n\nimport type { AppleSession } from \"../client/apple-session.js\";\n\nconst IRIS_BASE = \"https://appstoreconnect.apple.com/iris/v1\";\nconst OLYMPUS_SESSION = \"https://appstoreconnect.apple.com/olympus/v1/session\";\n\n/** Every category App Store Connect accepts. Anything else is refused before existing answers are deleted. */\nexport const DATA_USAGE_CATEGORIES = [\n \"PAYMENT_INFORMATION\", \"CREDIT_AND_FRAUD\", \"OTHER_FINANCIAL_INFO\",\n \"PRECISE_LOCATION\", \"COARSE_LOCATION\", \"SENSITIVE_INFO\",\n \"PHYSICAL_ADDRESS\", \"EMAIL_ADDRESS\", \"NAME\", \"PHONE_NUMBER\", \"OTHER_CONTACT_INFO\",\n \"CONTACTS\", \"EMAILS_OR_TEXT_MESSAGES\", \"PHOTOS_OR_VIDEOS\", \"AUDIO\", \"GAMEPLAY_CONTENT\",\n \"CUSTOMER_SUPPORT\", \"OTHER_USER_CONTENT\", \"BROWSING_HISTORY\", \"SEARCH_HISTORY\",\n \"USER_ID\", \"DEVICE_ID\", \"PURCHASE_HISTORY\", \"PRODUCT_INTERACTION\", \"ADVERTISING_DATA\",\n \"OTHER_USAGE_DATA\", \"CRASH_DATA\", \"PERFORMANCE_DATA\", \"OTHER_DIAGNOSTIC_DATA\",\n \"OTHER_DATA\", \"HEALTH\", \"FITNESS\",\n] as const;\nexport const DATA_USAGE_PURPOSES = [\n \"THIRD_PARTY_ADVERTISING\", \"DEVELOPERS_ADVERTISING\", \"ANALYTICS\",\n \"PRODUCT_PERSONALIZATION\", \"APP_FUNCTIONALITY\", \"OTHER_PURPOSES\",\n] as const;\nexport const DATA_PROTECTIONS = [\n \"DATA_USED_TO_TRACK_YOU\", \"DATA_LINKED_TO_YOU\", \"DATA_NOT_LINKED_TO_YOU\", \"DATA_NOT_COLLECTED\",\n] as const;\n\nexport type DataUsageCategory =\n | \"PAYMENT_INFORMATION\" | \"CREDIT_AND_FRAUD\" | \"OTHER_FINANCIAL_INFO\"\n | \"PRECISE_LOCATION\" | \"COARSE_LOCATION\" | \"SENSITIVE_INFO\"\n | \"PHYSICAL_ADDRESS\" | \"EMAIL_ADDRESS\" | \"NAME\" | \"PHONE_NUMBER\" | \"OTHER_CONTACT_INFO\"\n | \"CONTACTS\" | \"EMAILS_OR_TEXT_MESSAGES\" | \"PHOTOS_OR_VIDEOS\" | \"AUDIO\" | \"GAMEPLAY_CONTENT\"\n | \"CUSTOMER_SUPPORT\" | \"OTHER_USER_CONTENT\" | \"BROWSING_HISTORY\" | \"SEARCH_HISTORY\"\n | \"USER_ID\" | \"DEVICE_ID\" | \"PURCHASE_HISTORY\" | \"PRODUCT_INTERACTION\" | \"ADVERTISING_DATA\"\n | \"OTHER_USAGE_DATA\" | \"CRASH_DATA\" | \"PERFORMANCE_DATA\" | \"OTHER_DIAGNOSTIC_DATA\"\n | \"OTHER_DATA\" | \"HEALTH\" | \"FITNESS\";\n\nexport type DataUsagePurpose =\n | \"THIRD_PARTY_ADVERTISING\" | \"DEVELOPERS_ADVERTISING\" | \"ANALYTICS\"\n | \"PRODUCT_PERSONALIZATION\" | \"APP_FUNCTIONALITY\" | \"OTHER_PURPOSES\";\n\nexport type DataProtection =\n | \"DATA_USED_TO_TRACK_YOU\" | \"DATA_LINKED_TO_YOU\" | \"DATA_NOT_LINKED_TO_YOU\" | \"DATA_NOT_COLLECTED\";\n\n/** One entry of Fastlane's app_privacy_details.json. */\nexport interface AppPrivacyUsage {\n category?: DataUsageCategory;\n purposes?: DataUsagePurpose[];\n data_protections: DataProtection[];\n}\n\nexport interface UploadAppPrivacyOptions {\n session: AppleSession;\n /** App Store Connect app id (the numeric Apple ID). */\n appId: string;\n usages: AppPrivacyUsage[];\n /** Leave the answers saved but unpublished (Fastlane's skip_publish). */\n skipPublish?: boolean;\n onLog?: (msg: string) => void;\n}\n\nexport interface UploadAppPrivacyResult {\n deleted: number;\n created: number;\n published: boolean;\n}\n\ninterface IrisResponse { status: number; body: any; text: string }\n\nasync function iris(session: AppleSession, method: string, path: string, body?: unknown): Promise<IrisResponse> {\n const res = await fetch(path.startsWith(\"http\") ? path : `${IRIS_BASE}${path}`, {\n method,\n headers: {\n Cookie: cookieHeader(session),\n Accept: \"application/vnd.api+json, application/json\",\n \"Content-Type\": \"application/vnd.api+json\",\n \"X-Requested-With\": \"XMLHttpRequest\",\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n absorbCookies(session, res);\n const text = await res.text();\n let parsed: any = null;\n try { parsed = text ? JSON.parse(text) : null; } catch { /* not JSON */ }\n return { status: res.status, body: parsed, text };\n}\n\nfunction cookieHeader(session: AppleSession): string {\n return Object.entries(session.cookies).map(([k, v]) => `${k}=${v}`).join(\"; \");\n}\n\nfunction absorbCookies(session: AppleSession, res: Response): void {\n for (const raw of res.headers.getSetCookie?.() ?? []) {\n const m = raw.match(/^([^=]+)=([^;]*)/);\n if (m) session.cookies[m[1]] = m[2];\n }\n}\n\nfunction fail(what: string, r: IrisResponse): never {\n const detail = r.body?.errors?.map((e: any) => e.detail ?? e.title).join(\"; \") || r.text.slice(0, 300);\n throw new Error(`${what} failed (HTTP ${r.status}): ${detail}`);\n}\n\n/**\n * Point the session at the App Store Connect provider (team) that owns the app.\n *\n * An Apple ID in several teams signs in to whichever one it used last, and\n * iris answers 404 for another team's app. Spaceship's `select_team` does the\n * same switch: POST the provider id to the olympus session.\n */\nexport async function selectProviderForApp(session: AppleSession, appId: string, onLog?: (m: string) => void): Promise<void> {\n const owns = async () => (await iris(session, \"GET\", `/apps/${appId}?fields[apps]=name`)).status === 200;\n if (await owns()) return;\n\n const res = await fetch(OLYMPUS_SESSION, { headers: { Cookie: cookieHeader(session), Accept: \"application/json\" } });\n absorbCookies(session, res);\n const info: any = await res.json().catch(() => null);\n const providers: Array<{ providerId: number; name: string }> = info?.availableProviders ?? [];\n for (const p of providers) {\n const sw = await fetch(OLYMPUS_SESSION, {\n method: \"POST\",\n headers: { Cookie: cookieHeader(session), \"Content-Type\": \"application/json\", Accept: \"application/json\" },\n body: JSON.stringify({ provider: { providerId: p.providerId } }),\n });\n absorbCookies(session, sw);\n if (sw.ok && (await owns())) {\n onLog?.(`Switched to team \"${p.name}\"`);\n session.teamId = String(p.providerId);\n return;\n }\n }\n throw new Error(`None of this Apple ID's ${providers.length} teams can see app ${appId}.`);\n}\n\n/** Existing privacy answers for an app. */\nexport async function listAppDataUsages(session: AppleSession, appId: string): Promise<Array<{ id: string }>> {\n const all: Array<{ id: string }> = [];\n let next: string | null = `/apps/${appId}/dataUsages?include=category,grouping,purpose,dataProtection&limit=500`;\n while (next) {\n const r = await iris(session, \"GET\", next);\n if (r.status !== 200) fail(\"List app data usages\", r);\n all.push(...(r.body?.data ?? []).map((d: any) => ({ id: d.id })));\n next = r.body?.links?.next ?? null;\n }\n return all;\n}\n\n/** Spaceship AppDataUsage.create — relationships are sent only when given. */\nexport async function createAppDataUsage(\n session: AppleSession,\n input: { appId: string; category?: string | null; purpose?: string | null; dataProtection: string },\n): Promise<string> {\n const relationships: Record<string, unknown> = { app: { data: { type: \"apps\", id: input.appId } } };\n if (input.category) relationships.category = { data: { type: \"appDataUsageCategories\", id: input.category } };\n if (input.purpose) relationships.purpose = { data: { type: \"appDataUsagePurposes\", id: input.purpose } };\n relationships.dataProtection = { data: { type: \"appDataUsageDataProtections\", id: input.dataProtection } };\n const r = await iris(session, \"POST\", \"/appDataUsages\", { data: { type: \"appDataUsages\", relationships } });\n if (r.status !== 201 && r.status !== 200) fail(`Create ${input.category ?? \"\"} ${input.purpose ?? \"\"} ${input.dataProtection}`.replace(/\\s+/g, \" \"), r);\n return r.body?.data?.id;\n}\n\nexport async function deleteAppDataUsage(session: AppleSession, id: string): Promise<void> {\n const r = await iris(session, \"DELETE\", `/appDataUsages/${id}`);\n if (r.status !== 204 && r.status !== 200) fail(`Delete app data usage ${id}`, r);\n}\n\nexport async function getAppDataUsagesPublishState(session: AppleSession, appId: string): Promise<{ id: string; published: boolean }> {\n const r = await iris(session, \"GET\", `/apps/${appId}/dataUsagePublishState`);\n if (r.status !== 200) fail(\"Read privacy publish state\", r);\n return { id: r.body.data.id, published: Boolean(r.body.data.attributes?.published) };\n}\n\nexport async function publishAppDataUsages(session: AppleSession, publishStateId: string): Promise<void> {\n const r = await iris(session, \"PATCH\", `/appDataUsagesPublishState/${publishStateId}`, {\n data: { type: \"appDataUsagesPublishState\", id: publishStateId, attributes: { published: true } },\n });\n if (r.status !== 200) fail(\"Publish privacy details\", r);\n}\n\n/** Fastlane's `upload_app_privacy_details_to_app_store`. Replaces all answers, then publishes. */\nexport async function uploadAppPrivacyDetails(opts: UploadAppPrivacyOptions): Promise<UploadAppPrivacyResult> {\n const { session, appId, usages, skipPublish, onLog = () => {} } = opts;\n validateUsages(usages);\n await selectProviderForApp(session, appId, onLog);\n\n const existing = await listAppDataUsages(session, appId);\n onLog(`Deleting ${existing.length} existing answer${existing.length === 1 ? \"\" : \"s\"}`);\n for (const u of existing) await deleteAppDataUsage(session, u.id);\n\n let created = 0;\n for (const usage of usages) {\n // \"Not collected\" has no purposes but still needs one AppDataUsage, so\n // iterate over [null] — the same trick Fastlane uses.\n const purposes: Array<string | null> = usage.purposes?.length ? usage.purposes : [null];\n for (const purpose of purposes) {\n for (const protection of usage.data_protections) {\n onLog(protection === \"DATA_NOT_COLLECTED\"\n ? `Setting ${protection}`\n : `Setting ${usage.category} and ${purpose} to ${protection}`);\n await createAppDataUsage(session, { appId, category: usage.category ?? null, purpose, dataProtection: protection });\n created++;\n }\n }\n }\n\n if (skipPublish) {\n onLog(\"Skipping publish\");\n return { deleted: existing.length, created, published: false };\n }\n const state = await getAppDataUsagesPublishState(session, appId);\n await publishAppDataUsages(session, state.id);\n onLog(\"Published\");\n return { deleted: existing.length, created, published: true };\n}\n\n/** Catch the answers App Store Connect would refuse, before deleting what is there. */\nexport function validateUsages(usages: AppPrivacyUsage[]): void {\n if (!Array.isArray(usages) || usages.length === 0) throw new Error(\"No privacy usages given.\");\n const notCollected = usages.some((u) => u.data_protections?.includes(\"DATA_NOT_COLLECTED\"));\n if (notCollected && usages.length > 1) {\n throw new Error(\"DATA_NOT_COLLECTED must be the only entry: an app cannot both collect nothing and collect something.\");\n }\n const known = (list: readonly string[], v: string, what: string) => {\n if (!list.includes(v)) throw new Error(`\"${v}\" is not an App Store Connect ${what}. Use one of: ${list.join(\", \")}.`);\n };\n for (const u of usages) {\n if (!u.data_protections?.length) throw new Error(`${u.category ?? \"An entry\"} has no data_protections.`);\n // Checked here, before anything is deleted: App Store Connect refuses an\n // unknown id only when that one answer is created, halfway through.\n if (u.category) known(DATA_USAGE_CATEGORIES, u.category, \"data category\");\n for (const p of u.purposes ?? []) known(DATA_USAGE_PURPOSES, p, \"purpose\");\n for (const d of u.data_protections) known(DATA_PROTECTIONS, d, \"data protection\");\n if (u.data_protections.includes(\"DATA_NOT_COLLECTED\")) continue;\n if (!u.category) throw new Error(\"Every collected entry needs a category.\");\n if (!u.purposes?.length) throw new Error(`${u.category} needs at least one purpose.`);\n const linked = u.data_protections.includes(\"DATA_LINKED_TO_YOU\");\n const unlinked = u.data_protections.includes(\"DATA_NOT_LINKED_TO_YOU\");\n if (linked && unlinked) throw new Error(`${u.category} cannot be both linked and not linked to the user.`);\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/client/providers.ts","../../src/privacy/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * App Store Connect \"providers\": the teams an Apple ID belongs to, as App\n * Store Connect sees them. A web session works inside one provider at a time\n * — whichever the person used last — and everything iris creates (API keys,\n * app records) lands in that provider, not the developer-portal team the\n * portal calls were made for. Spaceship's `select_team` is the same switch.\n */\nimport type { AppleSession } from \"./apple-session.js\";\n\nconst OLYMPUS_SESSION = \"https://appstoreconnect.apple.com/olympus/v1/session\";\n\nexport interface AscProvider {\n providerId: number;\n name: string;\n}\n\nexport function cookieHeader(session: AppleSession): string {\n return Object.entries(session.cookies).map(([k, v]) => `${k}=${v}`).join(\"; \");\n}\n\nexport function absorbCookies(session: AppleSession, res: Response): void {\n for (const raw of res.headers.getSetCookie?.() ?? []) {\n const m = raw.match(/^([^=]+)=([^;]*)/);\n if (m) session.cookies[m[1]] = m[2];\n }\n}\n\n/** The provider the session is in now, and every provider it could switch to. */\nexport async function listProviders(session: AppleSession): Promise<{ current: AscProvider | null; providers: AscProvider[] }> {\n const res = await fetch(OLYMPUS_SESSION, { headers: { Cookie: cookieHeader(session), Accept: \"application/json\" } });\n absorbCookies(session, res);\n const info: any = await res.json().catch(() => null);\n const pick = (p: any): AscProvider | null =>\n p?.providerId != null ? { providerId: Number(p.providerId), name: String(p.name ?? p.providerId) } : null;\n const providers = ((info?.availableProviders ?? []) as any[]).map(pick).filter((p): p is AscProvider => !!p);\n return { current: pick(info?.provider), providers };\n}\n\n/** Move the session into another provider. True when Apple accepted it. */\nexport async function switchProvider(session: AppleSession, providerId: number): Promise<boolean> {\n const res = await fetch(OLYMPUS_SESSION, {\n method: \"POST\",\n headers: { Cookie: cookieHeader(session), \"Content-Type\": \"application/json\", Accept: \"application/json\" },\n body: JSON.stringify({ provider: { providerId } }),\n });\n absorbCookies(session, res);\n if (res.ok) session.teamId = String(providerId);\n return res.ok;\n}\n","/**\n * App Privacy details (\"nutrition labels\") for an app in App Store Connect.\n * 1:1 port of Fastlane's `upload_app_privacy_details_to_app_store` action and\n * Spaceship's AppDataUsage / AppDataUsagesPublishState models.\n *\n * The public App Store Connect API has no endpoint for privacy details — an\n * API key cannot set them. Fastlane goes through the iris API that App Store\n * Connect's own web UI uses, authenticated with an Apple ID session, and so\n * does this: pass the AppleSession from `loginWithAppleId` / the App Release\n * sign-in.\n *\n * Usages use Fastlane's JSON format, so an existing `app_privacy_details.json`\n * works unchanged:\n *\n * [\n * { \"category\": \"EMAIL_ADDRESS\", \"purposes\": [\"APP_FUNCTIONALITY\"], \"data_protections\": [\"DATA_LINKED_TO_YOU\"] },\n * { \"data_protections\": [\"DATA_NOT_COLLECTED\"] } // an app that collects nothing\n * ]\n *\n * As in Fastlane, the upload REPLACES everything: existing usages are deleted\n * first, then the new ones are created, then the answers are published.\n */\n\nimport type { AppleSession } from \"../client/apple-session.js\";\nimport { absorbCookies, cookieHeader, listProviders, switchProvider } from \"../client/providers.js\";\n\nconst IRIS_BASE = \"https://appstoreconnect.apple.com/iris/v1\";\n\n/** Every category App Store Connect accepts. Anything else is refused before existing answers are deleted. */\nexport const DATA_USAGE_CATEGORIES = [\n \"PAYMENT_INFORMATION\", \"CREDIT_AND_FRAUD\", \"OTHER_FINANCIAL_INFO\",\n \"PRECISE_LOCATION\", \"COARSE_LOCATION\", \"SENSITIVE_INFO\",\n \"PHYSICAL_ADDRESS\", \"EMAIL_ADDRESS\", \"NAME\", \"PHONE_NUMBER\", \"OTHER_CONTACT_INFO\",\n \"CONTACTS\", \"EMAILS_OR_TEXT_MESSAGES\", \"PHOTOS_OR_VIDEOS\", \"AUDIO\", \"GAMEPLAY_CONTENT\",\n \"CUSTOMER_SUPPORT\", \"OTHER_USER_CONTENT\", \"BROWSING_HISTORY\", \"SEARCH_HISTORY\",\n \"USER_ID\", \"DEVICE_ID\", \"PURCHASE_HISTORY\", \"PRODUCT_INTERACTION\", \"ADVERTISING_DATA\",\n \"OTHER_USAGE_DATA\", \"CRASH_DATA\", \"PERFORMANCE_DATA\", \"OTHER_DIAGNOSTIC_DATA\",\n \"OTHER_DATA\", \"HEALTH\", \"FITNESS\",\n] as const;\nexport const DATA_USAGE_PURPOSES = [\n \"THIRD_PARTY_ADVERTISING\", \"DEVELOPERS_ADVERTISING\", \"ANALYTICS\",\n \"PRODUCT_PERSONALIZATION\", \"APP_FUNCTIONALITY\", \"OTHER_PURPOSES\",\n] as const;\nexport const DATA_PROTECTIONS = [\n \"DATA_USED_TO_TRACK_YOU\", \"DATA_LINKED_TO_YOU\", \"DATA_NOT_LINKED_TO_YOU\", \"DATA_NOT_COLLECTED\",\n] as const;\n\nexport type DataUsageCategory =\n | \"PAYMENT_INFORMATION\" | \"CREDIT_AND_FRAUD\" | \"OTHER_FINANCIAL_INFO\"\n | \"PRECISE_LOCATION\" | \"COARSE_LOCATION\" | \"SENSITIVE_INFO\"\n | \"PHYSICAL_ADDRESS\" | \"EMAIL_ADDRESS\" | \"NAME\" | \"PHONE_NUMBER\" | \"OTHER_CONTACT_INFO\"\n | \"CONTACTS\" | \"EMAILS_OR_TEXT_MESSAGES\" | \"PHOTOS_OR_VIDEOS\" | \"AUDIO\" | \"GAMEPLAY_CONTENT\"\n | \"CUSTOMER_SUPPORT\" | \"OTHER_USER_CONTENT\" | \"BROWSING_HISTORY\" | \"SEARCH_HISTORY\"\n | \"USER_ID\" | \"DEVICE_ID\" | \"PURCHASE_HISTORY\" | \"PRODUCT_INTERACTION\" | \"ADVERTISING_DATA\"\n | \"OTHER_USAGE_DATA\" | \"CRASH_DATA\" | \"PERFORMANCE_DATA\" | \"OTHER_DIAGNOSTIC_DATA\"\n | \"OTHER_DATA\" | \"HEALTH\" | \"FITNESS\";\n\nexport type DataUsagePurpose =\n | \"THIRD_PARTY_ADVERTISING\" | \"DEVELOPERS_ADVERTISING\" | \"ANALYTICS\"\n | \"PRODUCT_PERSONALIZATION\" | \"APP_FUNCTIONALITY\" | \"OTHER_PURPOSES\";\n\nexport type DataProtection =\n | \"DATA_USED_TO_TRACK_YOU\" | \"DATA_LINKED_TO_YOU\" | \"DATA_NOT_LINKED_TO_YOU\" | \"DATA_NOT_COLLECTED\";\n\n/** One entry of Fastlane's app_privacy_details.json. */\nexport interface AppPrivacyUsage {\n category?: DataUsageCategory;\n purposes?: DataUsagePurpose[];\n data_protections: DataProtection[];\n}\n\nexport interface UploadAppPrivacyOptions {\n session: AppleSession;\n /** App Store Connect app id (the numeric Apple ID). */\n appId: string;\n usages: AppPrivacyUsage[];\n /** Leave the answers saved but unpublished (Fastlane's skip_publish). */\n skipPublish?: boolean;\n onLog?: (msg: string) => void;\n}\n\nexport interface UploadAppPrivacyResult {\n deleted: number;\n created: number;\n published: boolean;\n}\n\ninterface IrisResponse { status: number; body: any; text: string }\n\nasync function iris(session: AppleSession, method: string, path: string, body?: unknown): Promise<IrisResponse> {\n const res = await fetch(path.startsWith(\"http\") ? path : `${IRIS_BASE}${path}`, {\n method,\n headers: {\n Cookie: cookieHeader(session),\n Accept: \"application/vnd.api+json, application/json\",\n \"Content-Type\": \"application/vnd.api+json\",\n \"X-Requested-With\": \"XMLHttpRequest\",\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n absorbCookies(session, res);\n const text = await res.text();\n let parsed: any = null;\n try { parsed = text ? JSON.parse(text) : null; } catch { /* not JSON */ }\n return { status: res.status, body: parsed, text };\n}\n\n\nfunction fail(what: string, r: IrisResponse): never {\n const detail = r.body?.errors?.map((e: any) => e.detail ?? e.title).join(\"; \") || r.text.slice(0, 300);\n throw new Error(`${what} failed (HTTP ${r.status}): ${detail}`);\n}\n\n/**\n * Point the session at the App Store Connect provider (team) that owns the app.\n *\n * An Apple ID in several teams signs in to whichever one it used last, and\n * iris answers 404 for another team's app. Spaceship's `select_team` does the\n * same switch: POST the provider id to the olympus session.\n */\nexport async function selectProviderForApp(session: AppleSession, appId: string, onLog?: (m: string) => void): Promise<void> {\n const owns = async () => (await iris(session, \"GET\", `/apps/${appId}?fields[apps]=name`)).status === 200;\n if (await owns()) return;\n\n const { providers } = await listProviders(session);\n for (const p of providers) {\n if ((await switchProvider(session, p.providerId)) && (await owns())) {\n onLog?.(`Switched to team \"${p.name}\"`);\n return;\n }\n }\n throw new Error(`None of this Apple ID's ${providers.length} teams can see app ${appId}.`);\n}\n\n/** Existing privacy answers for an app. */\nexport async function listAppDataUsages(session: AppleSession, appId: string): Promise<Array<{ id: string }>> {\n const all: Array<{ id: string }> = [];\n let next: string | null = `/apps/${appId}/dataUsages?include=category,grouping,purpose,dataProtection&limit=500`;\n while (next) {\n const r = await iris(session, \"GET\", next);\n if (r.status !== 200) fail(\"List app data usages\", r);\n all.push(...(r.body?.data ?? []).map((d: any) => ({ id: d.id })));\n next = r.body?.links?.next ?? null;\n }\n return all;\n}\n\n/** Spaceship AppDataUsage.create — relationships are sent only when given. */\nexport async function createAppDataUsage(\n session: AppleSession,\n input: { appId: string; category?: string | null; purpose?: string | null; dataProtection: string },\n): Promise<string> {\n const relationships: Record<string, unknown> = { app: { data: { type: \"apps\", id: input.appId } } };\n if (input.category) relationships.category = { data: { type: \"appDataUsageCategories\", id: input.category } };\n if (input.purpose) relationships.purpose = { data: { type: \"appDataUsagePurposes\", id: input.purpose } };\n relationships.dataProtection = { data: { type: \"appDataUsageDataProtections\", id: input.dataProtection } };\n const r = await iris(session, \"POST\", \"/appDataUsages\", { data: { type: \"appDataUsages\", relationships } });\n if (r.status !== 201 && r.status !== 200) fail(`Create ${input.category ?? \"\"} ${input.purpose ?? \"\"} ${input.dataProtection}`.replace(/\\s+/g, \" \"), r);\n return r.body?.data?.id;\n}\n\nexport async function deleteAppDataUsage(session: AppleSession, id: string): Promise<void> {\n const r = await iris(session, \"DELETE\", `/appDataUsages/${id}`);\n if (r.status !== 204 && r.status !== 200) fail(`Delete app data usage ${id}`, r);\n}\n\nexport async function getAppDataUsagesPublishState(session: AppleSession, appId: string): Promise<{ id: string; published: boolean }> {\n const r = await iris(session, \"GET\", `/apps/${appId}/dataUsagePublishState`);\n if (r.status !== 200) fail(\"Read privacy publish state\", r);\n return { id: r.body.data.id, published: Boolean(r.body.data.attributes?.published) };\n}\n\nexport async function publishAppDataUsages(session: AppleSession, publishStateId: string): Promise<void> {\n const r = await iris(session, \"PATCH\", `/appDataUsagesPublishState/${publishStateId}`, {\n data: { type: \"appDataUsagesPublishState\", id: publishStateId, attributes: { published: true } },\n });\n if (r.status !== 200) fail(\"Publish privacy details\", r);\n}\n\n/** Fastlane's `upload_app_privacy_details_to_app_store`. Replaces all answers, then publishes. */\nexport async function uploadAppPrivacyDetails(opts: UploadAppPrivacyOptions): Promise<UploadAppPrivacyResult> {\n const { session, appId, usages, skipPublish, onLog = () => {} } = opts;\n validateUsages(usages);\n await selectProviderForApp(session, appId, onLog);\n\n const existing = await listAppDataUsages(session, appId);\n onLog(`Deleting ${existing.length} existing answer${existing.length === 1 ? \"\" : \"s\"}`);\n for (const u of existing) await deleteAppDataUsage(session, u.id);\n\n let created = 0;\n for (const usage of usages) {\n // \"Not collected\" has no purposes but still needs one AppDataUsage, so\n // iterate over [null] — the same trick Fastlane uses.\n const purposes: Array<string | null> = usage.purposes?.length ? usage.purposes : [null];\n for (const purpose of purposes) {\n for (const protection of usage.data_protections) {\n onLog(protection === \"DATA_NOT_COLLECTED\"\n ? `Setting ${protection}`\n : `Setting ${usage.category} and ${purpose} to ${protection}`);\n await createAppDataUsage(session, { appId, category: usage.category ?? null, purpose, dataProtection: protection });\n created++;\n }\n }\n }\n\n if (skipPublish) {\n onLog(\"Skipping publish\");\n return { deleted: existing.length, created, published: false };\n }\n const state = await getAppDataUsagesPublishState(session, appId);\n await publishAppDataUsages(session, state.id);\n onLog(\"Published\");\n return { deleted: existing.length, created, published: true };\n}\n\n/** Catch the answers App Store Connect would refuse, before deleting what is there. */\nexport function validateUsages(usages: AppPrivacyUsage[]): void {\n if (!Array.isArray(usages) || usages.length === 0) throw new Error(\"No privacy usages given.\");\n const notCollected = usages.some((u) => u.data_protections?.includes(\"DATA_NOT_COLLECTED\"));\n if (notCollected && usages.length > 1) {\n throw new Error(\"DATA_NOT_COLLECTED must be the only entry: an app cannot both collect nothing and collect something.\");\n }\n const known = (list: readonly string[], v: string, what: string) => {\n if (!list.includes(v)) throw new Error(`\"${v}\" is not an App Store Connect ${what}. Use one of: ${list.join(\", \")}.`);\n };\n for (const u of usages) {\n if (!u.data_protections?.length) throw new Error(`${u.category ?? \"An entry\"} has no data_protections.`);\n // Checked here, before anything is deleted: App Store Connect refuses an\n // unknown id only when that one answer is created, halfway through.\n if (u.category) known(DATA_USAGE_CATEGORIES, u.category, \"data category\");\n for (const p of u.purposes ?? []) known(DATA_USAGE_PURPOSES, p, \"purpose\");\n for (const d of u.data_protections) known(DATA_PROTECTIONS, d, \"data protection\");\n if (u.data_protections.includes(\"DATA_NOT_COLLECTED\")) continue;\n if (!u.category) throw new Error(\"Every collected entry needs a category.\");\n if (!u.purposes?.length) throw new Error(`${u.category} needs at least one purpose.`);\n const linked = u.data_protections.includes(\"DATA_LINKED_TO_YOU\");\n const unlinked = u.data_protections.includes(\"DATA_NOT_LINKED_TO_YOU\");\n if (linked && unlinked) throw new Error(`${u.category} cannot be both linked and not linked to the user.`);\n }\n}\n"]}
@@ -1,2 +1,2 @@
1
- import '../apple-session-jUzBrql5.cjs';
2
- export { A as AppPrivacyUsage, b as DATA_PROTECTIONS, D as DATA_USAGE_CATEGORIES, a as DATA_USAGE_PURPOSES, e as DataProtection, c as DataUsageCategory, d as DataUsagePurpose, U as UploadAppPrivacyOptions, f as UploadAppPrivacyResult, g as createAppDataUsage, h as deleteAppDataUsage, j as getAppDataUsagesPublishState, l as listAppDataUsages, p as publishAppDataUsages, s as selectProviderForApp, u as uploadAppPrivacyDetails, v as validateUsages } from '../index-DnHQ2uT2.cjs';
1
+ import '../apple-session-D6x7Jo3D.cjs';
2
+ export { A as AppPrivacyUsage, D as DATA_PROTECTIONS, a as DATA_USAGE_CATEGORIES, b as DATA_USAGE_PURPOSES, c as DataProtection, d as DataUsageCategory, e as DataUsagePurpose, U as UploadAppPrivacyOptions, f as UploadAppPrivacyResult, g as createAppDataUsage, h as deleteAppDataUsage, j as getAppDataUsagesPublishState, l as listAppDataUsages, p as publishAppDataUsages, s as selectProviderForApp, u as uploadAppPrivacyDetails, v as validateUsages } from '../index-258t9n7v.cjs';
@@ -1,2 +1,2 @@
1
- import '../apple-session-jUzBrql5.js';
2
- export { A as AppPrivacyUsage, b as DATA_PROTECTIONS, D as DATA_USAGE_CATEGORIES, a as DATA_USAGE_PURPOSES, e as DataProtection, c as DataUsageCategory, d as DataUsagePurpose, U as UploadAppPrivacyOptions, f as UploadAppPrivacyResult, g as createAppDataUsage, h as deleteAppDataUsage, j as getAppDataUsagesPublishState, l as listAppDataUsages, p as publishAppDataUsages, s as selectProviderForApp, u as uploadAppPrivacyDetails, v as validateUsages } from '../index-8djTPW8O.js';
1
+ import '../apple-session-D6x7Jo3D.js';
2
+ export { A as AppPrivacyUsage, D as DATA_PROTECTIONS, a as DATA_USAGE_CATEGORIES, b as DATA_USAGE_PURPOSES, c as DataProtection, d as DataUsageCategory, e as DataUsagePurpose, U as UploadAppPrivacyOptions, f as UploadAppPrivacyResult, g as createAppDataUsage, h as deleteAppDataUsage, j as getAppDataUsagesPublishState, l as listAppDataUsages, p as publishAppDataUsages, s as selectProviderForApp, u as uploadAppPrivacyDetails, v as validateUsages } from '../index-BmrOdmNL.js';
@@ -1,6 +1,35 @@
1
+ // src/client/providers.ts
2
+ var OLYMPUS_SESSION = "https://appstoreconnect.apple.com/olympus/v1/session";
3
+ function cookieHeader(session) {
4
+ return Object.entries(session.cookies).map(([k, v]) => `${k}=${v}`).join("; ");
5
+ }
6
+ function absorbCookies(session, res) {
7
+ for (const raw of res.headers.getSetCookie?.() ?? []) {
8
+ const m = raw.match(/^([^=]+)=([^;]*)/);
9
+ if (m) session.cookies[m[1]] = m[2];
10
+ }
11
+ }
12
+ async function listProviders(session) {
13
+ const res = await fetch(OLYMPUS_SESSION, { headers: { Cookie: cookieHeader(session), Accept: "application/json" } });
14
+ absorbCookies(session, res);
15
+ const info = await res.json().catch(() => null);
16
+ const pick = (p) => p?.providerId != null ? { providerId: Number(p.providerId), name: String(p.name ?? p.providerId) } : null;
17
+ const providers = (info?.availableProviders ?? []).map(pick).filter((p) => !!p);
18
+ return { current: pick(info?.provider), providers };
19
+ }
20
+ async function switchProvider(session, providerId) {
21
+ const res = await fetch(OLYMPUS_SESSION, {
22
+ method: "POST",
23
+ headers: { Cookie: cookieHeader(session), "Content-Type": "application/json", Accept: "application/json" },
24
+ body: JSON.stringify({ provider: { providerId } })
25
+ });
26
+ absorbCookies(session, res);
27
+ if (res.ok) session.teamId = String(providerId);
28
+ return res.ok;
29
+ }
30
+
1
31
  // src/privacy/index.ts
2
32
  var IRIS_BASE = "https://appstoreconnect.apple.com/iris/v1";
3
- var OLYMPUS_SESSION = "https://appstoreconnect.apple.com/olympus/v1/session";
4
33
  var DATA_USAGE_CATEGORIES = [
5
34
  "PAYMENT_INFORMATION",
6
35
  "CREDIT_AND_FRAUD",
@@ -69,15 +98,6 @@ async function iris(session, method, path, body) {
69
98
  }
70
99
  return { status: res.status, body: parsed, text };
71
100
  }
72
- function cookieHeader(session) {
73
- return Object.entries(session.cookies).map(([k, v]) => `${k}=${v}`).join("; ");
74
- }
75
- function absorbCookies(session, res) {
76
- for (const raw of res.headers.getSetCookie?.() ?? []) {
77
- const m = raw.match(/^([^=]+)=([^;]*)/);
78
- if (m) session.cookies[m[1]] = m[2];
79
- }
80
- }
81
101
  function fail(what, r) {
82
102
  const detail = r.body?.errors?.map((e) => e.detail ?? e.title).join("; ") || r.text.slice(0, 300);
83
103
  throw new Error(`${what} failed (HTTP ${r.status}): ${detail}`);
@@ -85,20 +105,10 @@ function fail(what, r) {
85
105
  async function selectProviderForApp(session, appId, onLog) {
86
106
  const owns = async () => (await iris(session, "GET", `/apps/${appId}?fields[apps]=name`)).status === 200;
87
107
  if (await owns()) return;
88
- const res = await fetch(OLYMPUS_SESSION, { headers: { Cookie: cookieHeader(session), Accept: "application/json" } });
89
- absorbCookies(session, res);
90
- const info = await res.json().catch(() => null);
91
- const providers = info?.availableProviders ?? [];
108
+ const { providers } = await listProviders(session);
92
109
  for (const p of providers) {
93
- const sw = await fetch(OLYMPUS_SESSION, {
94
- method: "POST",
95
- headers: { Cookie: cookieHeader(session), "Content-Type": "application/json", Accept: "application/json" },
96
- body: JSON.stringify({ provider: { providerId: p.providerId } })
97
- });
98
- absorbCookies(session, sw);
99
- if (sw.ok && await owns()) {
110
+ if (await switchProvider(session, p.providerId) && await owns()) {
100
111
  onLog?.(`Switched to team "${p.name}"`);
101
- session.teamId = String(p.providerId);
102
112
  return;
103
113
  }
104
114
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/privacy/index.ts"],"names":[],"mappings":";AAyBA,IAAM,SAAA,GAAY,2CAAA;AAClB,IAAM,eAAA,GAAkB,sDAAA;AAGjB,IAAM,qBAAA,GAAwB;AAAA,EACnC,qBAAA;AAAA,EAAuB,kBAAA;AAAA,EAAoB,sBAAA;AAAA,EAC3C,kBAAA;AAAA,EAAoB,iBAAA;AAAA,EAAmB,gBAAA;AAAA,EACvC,kBAAA;AAAA,EAAoB,eAAA;AAAA,EAAiB,MAAA;AAAA,EAAQ,cAAA;AAAA,EAAgB,oBAAA;AAAA,EAC7D,UAAA;AAAA,EAAY,yBAAA;AAAA,EAA2B,kBAAA;AAAA,EAAoB,OAAA;AAAA,EAAS,kBAAA;AAAA,EACpE,kBAAA;AAAA,EAAoB,oBAAA;AAAA,EAAsB,kBAAA;AAAA,EAAoB,gBAAA;AAAA,EAC9D,SAAA;AAAA,EAAW,WAAA;AAAA,EAAa,kBAAA;AAAA,EAAoB,qBAAA;AAAA,EAAuB,kBAAA;AAAA,EACnE,kBAAA;AAAA,EAAoB,YAAA;AAAA,EAAc,kBAAA;AAAA,EAAoB,uBAAA;AAAA,EACtD,YAAA;AAAA,EAAc,QAAA;AAAA,EAAU;AAC1B;AACO,IAAM,mBAAA,GAAsB;AAAA,EACjC,yBAAA;AAAA,EAA2B,wBAAA;AAAA,EAA0B,WAAA;AAAA,EACrD,yBAAA;AAAA,EAA2B,mBAAA;AAAA,EAAqB;AAClD;AACO,IAAM,gBAAA,GAAmB;AAAA,EAC9B,wBAAA;AAAA,EAA0B,oBAAA;AAAA,EAAsB,wBAAA;AAAA,EAA0B;AAC5E;AA4CA,eAAe,IAAA,CAAK,OAAA,EAAuB,MAAA,EAAgB,IAAA,EAAc,IAAA,EAAuC;AAC9G,EAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,IAAA,CAAK,UAAA,CAAW,MAAM,CAAA,GAAI,IAAA,GAAO,CAAA,EAAG,SAAS,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI;AAAA,IAC9E,MAAA;AAAA,IACA,OAAA,EAAS;AAAA,MACP,MAAA,EAAQ,aAAa,OAAO,CAAA;AAAA,MAC5B,MAAA,EAAQ,4CAAA;AAAA,MACR,cAAA,EAAgB,0BAAA;AAAA,MAChB,kBAAA,EAAoB;AAAA,KACtB;AAAA,IACA,IAAA,EAAM,IAAA,GAAO,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA,GAAI;AAAA,GACrC,CAAA;AACD,EAAA,aAAA,CAAc,SAAS,GAAG,CAAA;AAC1B,EAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK;AAC5B,EAAA,IAAI,MAAA,GAAc,IAAA;AAClB,EAAA,IAAI;AAAE,IAAA,MAAA,GAAS,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA,GAAI,IAAA;AAAA,EAAM,CAAA,CAAA,MAAQ;AAAA,EAAiB;AACxE,EAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,CAAI,MAAA,EAAQ,IAAA,EAAM,QAAQ,IAAA,EAAK;AAClD;AAEA,SAAS,aAAa,OAAA,EAA+B;AACnD,EAAA,OAAO,OAAO,OAAA,CAAQ,OAAA,CAAQ,OAAO,CAAA,CAAE,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG,CAAC,CAAA,KAAM,GAAG,CAAC,CAAA,CAAA,EAAI,CAAC,CAAA,CAAE,CAAA,CAAE,KAAK,IAAI,CAAA;AAC/E;AAEA,SAAS,aAAA,CAAc,SAAuB,GAAA,EAAqB;AACjE,EAAA,KAAA,MAAW,OAAO,GAAA,CAAI,OAAA,CAAQ,YAAA,IAAe,IAAK,EAAC,EAAG;AACpD,IAAA,MAAM,CAAA,GAAI,GAAA,CAAI,KAAA,CAAM,kBAAkB,CAAA;AACtC,IAAA,IAAI,CAAA,UAAW,OAAA,CAAQ,CAAA,CAAE,CAAC,CAAC,CAAA,GAAI,EAAE,CAAC,CAAA;AAAA,EACpC;AACF;AAEA,SAAS,IAAA,CAAK,MAAc,CAAA,EAAwB;AAClD,EAAA,MAAM,SAAS,CAAA,CAAE,IAAA,EAAM,QAAQ,GAAA,CAAI,CAAC,MAAW,CAAA,CAAE,MAAA,IAAU,EAAE,KAAK,CAAA,CAAE,KAAK,IAAI,CAAA,IAAK,EAAE,IAAA,CAAK,KAAA,CAAM,GAAG,GAAG,CAAA;AACrG,EAAA,MAAM,IAAI,MAAM,CAAA,EAAG,IAAI,iBAAiB,CAAA,CAAE,MAAM,CAAA,GAAA,EAAM,MAAM,CAAA,CAAE,CAAA;AAChE;AASA,eAAsB,oBAAA,CAAqB,OAAA,EAAuB,KAAA,EAAe,KAAA,EAA4C;AAC3H,EAAA,MAAM,IAAA,GAAO,YAAA,CAAa,MAAM,IAAA,CAAK,OAAA,EAAS,OAAO,CAAA,MAAA,EAAS,KAAK,CAAA,kBAAA,CAAoB,CAAA,EAAG,MAAA,KAAW,GAAA;AACrG,EAAA,IAAI,MAAM,MAAK,EAAG;AAElB,EAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,eAAA,EAAiB,EAAE,OAAA,EAAS,EAAE,MAAA,EAAQ,YAAA,CAAa,OAAO,CAAA,EAAG,MAAA,EAAQ,kBAAA,IAAsB,CAAA;AACnH,EAAA,aAAA,CAAc,SAAS,GAAG,CAAA;AAC1B,EAAA,MAAM,OAAY,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,IAAI,CAAA;AACnD,EAAA,MAAM,SAAA,GAAyD,IAAA,EAAM,kBAAA,IAAsB,EAAC;AAC5F,EAAA,KAAA,MAAW,KAAK,SAAA,EAAW;AACzB,IAAA,MAAM,EAAA,GAAK,MAAM,KAAA,CAAM,eAAA,EAAiB;AAAA,MACtC,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,MAAA,EAAQ,YAAA,CAAa,OAAO,CAAA,EAAG,cAAA,EAAgB,kBAAA,EAAoB,MAAA,EAAQ,kBAAA,EAAmB;AAAA,MACzG,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,EAAE,QAAA,EAAU,EAAE,UAAA,EAAY,CAAA,CAAE,UAAA,EAAW,EAAG;AAAA,KAChE,CAAA;AACD,IAAA,aAAA,CAAc,SAAS,EAAE,CAAA;AACzB,IAAA,IAAI,EAAA,CAAG,EAAA,IAAO,MAAM,IAAA,EAAK,EAAI;AAC3B,MAAA,KAAA,GAAQ,CAAA,kBAAA,EAAqB,CAAA,CAAE,IAAI,CAAA,CAAA,CAAG,CAAA;AACtC,MAAA,OAAA,CAAQ,MAAA,GAAS,MAAA,CAAO,CAAA,CAAE,UAAU,CAAA;AACpC,MAAA;AAAA,IACF;AAAA,EACF;AACA,EAAA,MAAM,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,UAAU,MAAM,CAAA,mBAAA,EAAsB,KAAK,CAAA,CAAA,CAAG,CAAA;AAC3F;AAGA,eAAsB,iBAAA,CAAkB,SAAuB,KAAA,EAA+C;AAC5G,EAAA,MAAM,MAA6B,EAAC;AACpC,EAAA,IAAI,IAAA,GAAsB,SAAS,KAAK,CAAA,sEAAA,CAAA;AACxC,EAAA,OAAO,IAAA,EAAM;AACX,IAAA,MAAM,CAAA,GAAI,MAAM,IAAA,CAAK,OAAA,EAAS,OAAO,IAAI,CAAA;AACzC,IAAA,IAAI,CAAA,CAAE,MAAA,KAAW,GAAA,EAAK,IAAA,CAAK,wBAAwB,CAAC,CAAA;AACpD,IAAA,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,IAAA,EAAM,QAAQ,EAAC,EAAG,GAAA,CAAI,CAAC,OAAY,EAAE,EAAA,EAAI,CAAA,CAAE,EAAA,GAAK,CAAC,CAAA;AAChE,IAAA,IAAA,GAAO,CAAA,CAAE,IAAA,EAAM,KAAA,EAAO,IAAA,IAAQ,IAAA;AAAA,EAChC;AACA,EAAA,OAAO,GAAA;AACT;AAGA,eAAsB,kBAAA,CACpB,SACA,KAAA,EACiB;AACjB,EAAA,MAAM,aAAA,GAAyC,EAAE,GAAA,EAAK,EAAE,IAAA,EAAM,EAAE,IAAA,EAAM,MAAA,EAAQ,EAAA,EAAI,KAAA,CAAM,KAAA,EAAM,EAAE,EAAE;AAClG,EAAA,IAAI,KAAA,CAAM,QAAA,EAAU,aAAA,CAAc,QAAA,GAAW,EAAE,IAAA,EAAM,EAAE,IAAA,EAAM,wBAAA,EAA0B,EAAA,EAAI,KAAA,CAAM,QAAA,EAAS,EAAE;AAC5G,EAAA,IAAI,KAAA,CAAM,OAAA,EAAS,aAAA,CAAc,OAAA,GAAU,EAAE,IAAA,EAAM,EAAE,IAAA,EAAM,sBAAA,EAAwB,EAAA,EAAI,KAAA,CAAM,OAAA,EAAQ,EAAE;AACvG,EAAA,aAAA,CAAc,cAAA,GAAiB,EAAE,IAAA,EAAM,EAAE,MAAM,6BAAA,EAA+B,EAAA,EAAI,KAAA,CAAM,cAAA,EAAe,EAAE;AACzG,EAAA,MAAM,CAAA,GAAI,MAAM,IAAA,CAAK,OAAA,EAAS,MAAA,EAAQ,gBAAA,EAAkB,EAAE,IAAA,EAAM,EAAE,IAAA,EAAM,eAAA,EAAiB,aAAA,IAAiB,CAAA;AAC1G,EAAA,IAAI,CAAA,CAAE,WAAW,GAAA,IAAO,CAAA,CAAE,WAAW,GAAA,EAAK,IAAA,CAAK,CAAA,OAAA,EAAU,KAAA,CAAM,QAAA,IAAY,EAAE,IAAI,KAAA,CAAM,OAAA,IAAW,EAAE,CAAA,CAAA,EAAI,KAAA,CAAM,cAAc,GAAG,OAAA,CAAQ,MAAA,EAAQ,GAAG,CAAA,EAAG,CAAC,CAAA;AACtJ,EAAA,OAAO,CAAA,CAAE,MAAM,IAAA,EAAM,EAAA;AACvB;AAEA,eAAsB,kBAAA,CAAmB,SAAuB,EAAA,EAA2B;AACzF,EAAA,MAAM,IAAI,MAAM,IAAA,CAAK,SAAS,QAAA,EAAU,CAAA,eAAA,EAAkB,EAAE,CAAA,CAAE,CAAA;AAC9D,EAAA,IAAI,CAAA,CAAE,MAAA,KAAW,GAAA,IAAO,CAAA,CAAE,MAAA,KAAW,KAAK,IAAA,CAAK,CAAA,sBAAA,EAAyB,EAAE,CAAA,CAAA,EAAI,CAAC,CAAA;AACjF;AAEA,eAAsB,4BAAA,CAA6B,SAAuB,KAAA,EAA4D;AACpI,EAAA,MAAM,IAAI,MAAM,IAAA,CAAK,SAAS,KAAA,EAAO,CAAA,MAAA,EAAS,KAAK,CAAA,sBAAA,CAAwB,CAAA;AAC3E,EAAA,IAAI,CAAA,CAAE,MAAA,KAAW,GAAA,EAAK,IAAA,CAAK,8BAA8B,CAAC,CAAA;AAC1D,EAAA,OAAO,EAAE,EAAA,EAAI,CAAA,CAAE,IAAA,CAAK,IAAA,CAAK,EAAA,EAAI,SAAA,EAAW,OAAA,CAAQ,CAAA,CAAE,IAAA,CAAK,IAAA,CAAK,UAAA,EAAY,SAAS,CAAA,EAAE;AACrF;AAEA,eAAsB,oBAAA,CAAqB,SAAuB,cAAA,EAAuC;AACvG,EAAA,MAAM,IAAI,MAAM,IAAA,CAAK,SAAS,OAAA,EAAS,CAAA,2BAAA,EAA8B,cAAc,CAAA,CAAA,EAAI;AAAA,IACrF,IAAA,EAAM,EAAE,IAAA,EAAM,2BAAA,EAA6B,EAAA,EAAI,gBAAgB,UAAA,EAAY,EAAE,SAAA,EAAW,IAAA,EAAK;AAAE,GAChG,CAAA;AACD,EAAA,IAAI,CAAA,CAAE,MAAA,KAAW,GAAA,EAAK,IAAA,CAAK,2BAA2B,CAAC,CAAA;AACzD;AAGA,eAAsB,wBAAwB,IAAA,EAAgE;AAC5G,EAAA,MAAM,EAAE,OAAA,EAAS,KAAA,EAAO,MAAA,EAAQ,WAAA,EAAa,QAAQ,MAAM;AAAA,EAAC,GAAE,GAAI,IAAA;AAClE,EAAA,cAAA,CAAe,MAAM,CAAA;AACrB,EAAA,MAAM,oBAAA,CAAqB,OAAA,EAAS,KAAA,EAAO,KAAK,CAAA;AAEhD,EAAA,MAAM,QAAA,GAAW,MAAM,iBAAA,CAAkB,OAAA,EAAS,KAAK,CAAA;AACvD,EAAA,KAAA,CAAM,CAAA,SAAA,EAAY,SAAS,MAAM,CAAA,gBAAA,EAAmB,SAAS,MAAA,KAAW,CAAA,GAAI,EAAA,GAAK,GAAG,CAAA,CAAE,CAAA;AACtF,EAAA,KAAA,MAAW,KAAK,QAAA,EAAU,MAAM,kBAAA,CAAmB,OAAA,EAAS,EAAE,EAAE,CAAA;AAEhE,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAG1B,IAAA,MAAM,WAAiC,KAAA,CAAM,QAAA,EAAU,SAAS,KAAA,CAAM,QAAA,GAAW,CAAC,IAAI,CAAA;AACtF,IAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,MAAA,KAAA,MAAW,UAAA,IAAc,MAAM,gBAAA,EAAkB;AAC/C,QAAA,KAAA,CAAM,UAAA,KAAe,oBAAA,GACjB,CAAA,QAAA,EAAW,UAAU,CAAA,CAAA,GACrB,CAAA,QAAA,EAAW,KAAA,CAAM,QAAQ,CAAA,KAAA,EAAQ,OAAO,CAAA,IAAA,EAAO,UAAU,CAAA,CAAE,CAAA;AAC/D,QAAA,MAAM,kBAAA,CAAmB,OAAA,EAAS,EAAE,KAAA,EAAO,QAAA,EAAU,KAAA,CAAM,QAAA,IAAY,IAAA,EAAM,OAAA,EAAS,cAAA,EAAgB,UAAA,EAAY,CAAA;AAClH,QAAA,OAAA,EAAA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,KAAA,CAAM,kBAAkB,CAAA;AACxB,IAAA,OAAO,EAAE,OAAA,EAAS,QAAA,CAAS,MAAA,EAAQ,OAAA,EAAS,WAAW,KAAA,EAAM;AAAA,EAC/D;AACA,EAAA,MAAM,KAAA,GAAQ,MAAM,4BAAA,CAA6B,OAAA,EAAS,KAAK,CAAA;AAC/D,EAAA,MAAM,oBAAA,CAAqB,OAAA,EAAS,KAAA,CAAM,EAAE,CAAA;AAC5C,EAAA,KAAA,CAAM,WAAW,CAAA;AACjB,EAAA,OAAO,EAAE,OAAA,EAAS,QAAA,CAAS,MAAA,EAAQ,OAAA,EAAS,WAAW,IAAA,EAAK;AAC9D;AAGO,SAAS,eAAe,MAAA,EAAiC;AAC9D,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,IAAK,MAAA,CAAO,MAAA,KAAW,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,0BAA0B,CAAA;AAC7F,EAAA,MAAM,YAAA,GAAe,OAAO,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,gBAAA,EAAkB,QAAA,CAAS,oBAAoB,CAAC,CAAA;AAC1F,EAAA,IAAI,YAAA,IAAgB,MAAA,CAAO,MAAA,GAAS,CAAA,EAAG;AACrC,IAAA,MAAM,IAAI,MAAM,sGAAsG,CAAA;AAAA,EACxH;AACA,EAAA,MAAM,KAAA,GAAQ,CAAC,IAAA,EAAyB,CAAA,EAAW,IAAA,KAAiB;AAClE,IAAA,IAAI,CAAC,IAAA,CAAK,QAAA,CAAS,CAAC,CAAA,QAAS,IAAI,KAAA,CAAM,CAAA,CAAA,EAAI,CAAC,iCAAiC,IAAI,CAAA,cAAA,EAAiB,KAAK,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,CAAG,CAAA;AAAA,EACtH,CAAA;AACA,EAAA,KAAA,MAAW,KAAK,MAAA,EAAQ;AACtB,IAAA,IAAI,CAAC,CAAA,CAAE,gBAAA,EAAkB,MAAA,EAAQ,MAAM,IAAI,KAAA,CAAM,CAAA,EAAG,CAAA,CAAE,QAAA,IAAY,UAAU,CAAA,yBAAA,CAA2B,CAAA;AAGvG,IAAA,IAAI,EAAE,QAAA,EAAU,KAAA,CAAM,qBAAA,EAAuB,CAAA,CAAE,UAAU,eAAe,CAAA;AACxE,IAAA,KAAA,MAAW,CAAA,IAAK,EAAE,QAAA,IAAY,IAAI,KAAA,CAAM,mBAAA,EAAqB,GAAG,SAAS,CAAA;AACzE,IAAA,KAAA,MAAW,KAAK,CAAA,CAAE,gBAAA,EAAkB,KAAA,CAAM,gBAAA,EAAkB,GAAG,iBAAiB,CAAA;AAChF,IAAA,IAAI,CAAA,CAAE,gBAAA,CAAiB,QAAA,CAAS,oBAAoB,CAAA,EAAG;AACvD,IAAA,IAAI,CAAC,CAAA,CAAE,QAAA,EAAU,MAAM,IAAI,MAAM,yCAAyC,CAAA;AAC1E,IAAA,IAAI,CAAC,CAAA,CAAE,QAAA,EAAU,MAAA,EAAQ,MAAM,IAAI,KAAA,CAAM,CAAA,EAAG,CAAA,CAAE,QAAQ,CAAA,4BAAA,CAA8B,CAAA;AACpF,IAAA,MAAM,MAAA,GAAS,CAAA,CAAE,gBAAA,CAAiB,QAAA,CAAS,oBAAoB,CAAA;AAC/D,IAAA,MAAM,QAAA,GAAW,CAAA,CAAE,gBAAA,CAAiB,QAAA,CAAS,wBAAwB,CAAA;AACrE,IAAA,IAAI,MAAA,IAAU,UAAU,MAAM,IAAI,MAAM,CAAA,EAAG,CAAA,CAAE,QAAQ,CAAA,kDAAA,CAAoD,CAAA;AAAA,EAC3G;AACF","file":"index.mjs","sourcesContent":["/**\n * App Privacy details (\"nutrition labels\") for an app in App Store Connect.\n * 1:1 port of Fastlane's `upload_app_privacy_details_to_app_store` action and\n * Spaceship's AppDataUsage / AppDataUsagesPublishState models.\n *\n * The public App Store Connect API has no endpoint for privacy details — an\n * API key cannot set them. Fastlane goes through the iris API that App Store\n * Connect's own web UI uses, authenticated with an Apple ID session, and so\n * does this: pass the AppleSession from `loginWithAppleId` / the App Release\n * sign-in.\n *\n * Usages use Fastlane's JSON format, so an existing `app_privacy_details.json`\n * works unchanged:\n *\n * [\n * { \"category\": \"EMAIL_ADDRESS\", \"purposes\": [\"APP_FUNCTIONALITY\"], \"data_protections\": [\"DATA_LINKED_TO_YOU\"] },\n * { \"data_protections\": [\"DATA_NOT_COLLECTED\"] } // an app that collects nothing\n * ]\n *\n * As in Fastlane, the upload REPLACES everything: existing usages are deleted\n * first, then the new ones are created, then the answers are published.\n */\n\nimport type { AppleSession } from \"../client/apple-session.js\";\n\nconst IRIS_BASE = \"https://appstoreconnect.apple.com/iris/v1\";\nconst OLYMPUS_SESSION = \"https://appstoreconnect.apple.com/olympus/v1/session\";\n\n/** Every category App Store Connect accepts. Anything else is refused before existing answers are deleted. */\nexport const DATA_USAGE_CATEGORIES = [\n \"PAYMENT_INFORMATION\", \"CREDIT_AND_FRAUD\", \"OTHER_FINANCIAL_INFO\",\n \"PRECISE_LOCATION\", \"COARSE_LOCATION\", \"SENSITIVE_INFO\",\n \"PHYSICAL_ADDRESS\", \"EMAIL_ADDRESS\", \"NAME\", \"PHONE_NUMBER\", \"OTHER_CONTACT_INFO\",\n \"CONTACTS\", \"EMAILS_OR_TEXT_MESSAGES\", \"PHOTOS_OR_VIDEOS\", \"AUDIO\", \"GAMEPLAY_CONTENT\",\n \"CUSTOMER_SUPPORT\", \"OTHER_USER_CONTENT\", \"BROWSING_HISTORY\", \"SEARCH_HISTORY\",\n \"USER_ID\", \"DEVICE_ID\", \"PURCHASE_HISTORY\", \"PRODUCT_INTERACTION\", \"ADVERTISING_DATA\",\n \"OTHER_USAGE_DATA\", \"CRASH_DATA\", \"PERFORMANCE_DATA\", \"OTHER_DIAGNOSTIC_DATA\",\n \"OTHER_DATA\", \"HEALTH\", \"FITNESS\",\n] as const;\nexport const DATA_USAGE_PURPOSES = [\n \"THIRD_PARTY_ADVERTISING\", \"DEVELOPERS_ADVERTISING\", \"ANALYTICS\",\n \"PRODUCT_PERSONALIZATION\", \"APP_FUNCTIONALITY\", \"OTHER_PURPOSES\",\n] as const;\nexport const DATA_PROTECTIONS = [\n \"DATA_USED_TO_TRACK_YOU\", \"DATA_LINKED_TO_YOU\", \"DATA_NOT_LINKED_TO_YOU\", \"DATA_NOT_COLLECTED\",\n] as const;\n\nexport type DataUsageCategory =\n | \"PAYMENT_INFORMATION\" | \"CREDIT_AND_FRAUD\" | \"OTHER_FINANCIAL_INFO\"\n | \"PRECISE_LOCATION\" | \"COARSE_LOCATION\" | \"SENSITIVE_INFO\"\n | \"PHYSICAL_ADDRESS\" | \"EMAIL_ADDRESS\" | \"NAME\" | \"PHONE_NUMBER\" | \"OTHER_CONTACT_INFO\"\n | \"CONTACTS\" | \"EMAILS_OR_TEXT_MESSAGES\" | \"PHOTOS_OR_VIDEOS\" | \"AUDIO\" | \"GAMEPLAY_CONTENT\"\n | \"CUSTOMER_SUPPORT\" | \"OTHER_USER_CONTENT\" | \"BROWSING_HISTORY\" | \"SEARCH_HISTORY\"\n | \"USER_ID\" | \"DEVICE_ID\" | \"PURCHASE_HISTORY\" | \"PRODUCT_INTERACTION\" | \"ADVERTISING_DATA\"\n | \"OTHER_USAGE_DATA\" | \"CRASH_DATA\" | \"PERFORMANCE_DATA\" | \"OTHER_DIAGNOSTIC_DATA\"\n | \"OTHER_DATA\" | \"HEALTH\" | \"FITNESS\";\n\nexport type DataUsagePurpose =\n | \"THIRD_PARTY_ADVERTISING\" | \"DEVELOPERS_ADVERTISING\" | \"ANALYTICS\"\n | \"PRODUCT_PERSONALIZATION\" | \"APP_FUNCTIONALITY\" | \"OTHER_PURPOSES\";\n\nexport type DataProtection =\n | \"DATA_USED_TO_TRACK_YOU\" | \"DATA_LINKED_TO_YOU\" | \"DATA_NOT_LINKED_TO_YOU\" | \"DATA_NOT_COLLECTED\";\n\n/** One entry of Fastlane's app_privacy_details.json. */\nexport interface AppPrivacyUsage {\n category?: DataUsageCategory;\n purposes?: DataUsagePurpose[];\n data_protections: DataProtection[];\n}\n\nexport interface UploadAppPrivacyOptions {\n session: AppleSession;\n /** App Store Connect app id (the numeric Apple ID). */\n appId: string;\n usages: AppPrivacyUsage[];\n /** Leave the answers saved but unpublished (Fastlane's skip_publish). */\n skipPublish?: boolean;\n onLog?: (msg: string) => void;\n}\n\nexport interface UploadAppPrivacyResult {\n deleted: number;\n created: number;\n published: boolean;\n}\n\ninterface IrisResponse { status: number; body: any; text: string }\n\nasync function iris(session: AppleSession, method: string, path: string, body?: unknown): Promise<IrisResponse> {\n const res = await fetch(path.startsWith(\"http\") ? path : `${IRIS_BASE}${path}`, {\n method,\n headers: {\n Cookie: cookieHeader(session),\n Accept: \"application/vnd.api+json, application/json\",\n \"Content-Type\": \"application/vnd.api+json\",\n \"X-Requested-With\": \"XMLHttpRequest\",\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n absorbCookies(session, res);\n const text = await res.text();\n let parsed: any = null;\n try { parsed = text ? JSON.parse(text) : null; } catch { /* not JSON */ }\n return { status: res.status, body: parsed, text };\n}\n\nfunction cookieHeader(session: AppleSession): string {\n return Object.entries(session.cookies).map(([k, v]) => `${k}=${v}`).join(\"; \");\n}\n\nfunction absorbCookies(session: AppleSession, res: Response): void {\n for (const raw of res.headers.getSetCookie?.() ?? []) {\n const m = raw.match(/^([^=]+)=([^;]*)/);\n if (m) session.cookies[m[1]] = m[2];\n }\n}\n\nfunction fail(what: string, r: IrisResponse): never {\n const detail = r.body?.errors?.map((e: any) => e.detail ?? e.title).join(\"; \") || r.text.slice(0, 300);\n throw new Error(`${what} failed (HTTP ${r.status}): ${detail}`);\n}\n\n/**\n * Point the session at the App Store Connect provider (team) that owns the app.\n *\n * An Apple ID in several teams signs in to whichever one it used last, and\n * iris answers 404 for another team's app. Spaceship's `select_team` does the\n * same switch: POST the provider id to the olympus session.\n */\nexport async function selectProviderForApp(session: AppleSession, appId: string, onLog?: (m: string) => void): Promise<void> {\n const owns = async () => (await iris(session, \"GET\", `/apps/${appId}?fields[apps]=name`)).status === 200;\n if (await owns()) return;\n\n const res = await fetch(OLYMPUS_SESSION, { headers: { Cookie: cookieHeader(session), Accept: \"application/json\" } });\n absorbCookies(session, res);\n const info: any = await res.json().catch(() => null);\n const providers: Array<{ providerId: number; name: string }> = info?.availableProviders ?? [];\n for (const p of providers) {\n const sw = await fetch(OLYMPUS_SESSION, {\n method: \"POST\",\n headers: { Cookie: cookieHeader(session), \"Content-Type\": \"application/json\", Accept: \"application/json\" },\n body: JSON.stringify({ provider: { providerId: p.providerId } }),\n });\n absorbCookies(session, sw);\n if (sw.ok && (await owns())) {\n onLog?.(`Switched to team \"${p.name}\"`);\n session.teamId = String(p.providerId);\n return;\n }\n }\n throw new Error(`None of this Apple ID's ${providers.length} teams can see app ${appId}.`);\n}\n\n/** Existing privacy answers for an app. */\nexport async function listAppDataUsages(session: AppleSession, appId: string): Promise<Array<{ id: string }>> {\n const all: Array<{ id: string }> = [];\n let next: string | null = `/apps/${appId}/dataUsages?include=category,grouping,purpose,dataProtection&limit=500`;\n while (next) {\n const r = await iris(session, \"GET\", next);\n if (r.status !== 200) fail(\"List app data usages\", r);\n all.push(...(r.body?.data ?? []).map((d: any) => ({ id: d.id })));\n next = r.body?.links?.next ?? null;\n }\n return all;\n}\n\n/** Spaceship AppDataUsage.create — relationships are sent only when given. */\nexport async function createAppDataUsage(\n session: AppleSession,\n input: { appId: string; category?: string | null; purpose?: string | null; dataProtection: string },\n): Promise<string> {\n const relationships: Record<string, unknown> = { app: { data: { type: \"apps\", id: input.appId } } };\n if (input.category) relationships.category = { data: { type: \"appDataUsageCategories\", id: input.category } };\n if (input.purpose) relationships.purpose = { data: { type: \"appDataUsagePurposes\", id: input.purpose } };\n relationships.dataProtection = { data: { type: \"appDataUsageDataProtections\", id: input.dataProtection } };\n const r = await iris(session, \"POST\", \"/appDataUsages\", { data: { type: \"appDataUsages\", relationships } });\n if (r.status !== 201 && r.status !== 200) fail(`Create ${input.category ?? \"\"} ${input.purpose ?? \"\"} ${input.dataProtection}`.replace(/\\s+/g, \" \"), r);\n return r.body?.data?.id;\n}\n\nexport async function deleteAppDataUsage(session: AppleSession, id: string): Promise<void> {\n const r = await iris(session, \"DELETE\", `/appDataUsages/${id}`);\n if (r.status !== 204 && r.status !== 200) fail(`Delete app data usage ${id}`, r);\n}\n\nexport async function getAppDataUsagesPublishState(session: AppleSession, appId: string): Promise<{ id: string; published: boolean }> {\n const r = await iris(session, \"GET\", `/apps/${appId}/dataUsagePublishState`);\n if (r.status !== 200) fail(\"Read privacy publish state\", r);\n return { id: r.body.data.id, published: Boolean(r.body.data.attributes?.published) };\n}\n\nexport async function publishAppDataUsages(session: AppleSession, publishStateId: string): Promise<void> {\n const r = await iris(session, \"PATCH\", `/appDataUsagesPublishState/${publishStateId}`, {\n data: { type: \"appDataUsagesPublishState\", id: publishStateId, attributes: { published: true } },\n });\n if (r.status !== 200) fail(\"Publish privacy details\", r);\n}\n\n/** Fastlane's `upload_app_privacy_details_to_app_store`. Replaces all answers, then publishes. */\nexport async function uploadAppPrivacyDetails(opts: UploadAppPrivacyOptions): Promise<UploadAppPrivacyResult> {\n const { session, appId, usages, skipPublish, onLog = () => {} } = opts;\n validateUsages(usages);\n await selectProviderForApp(session, appId, onLog);\n\n const existing = await listAppDataUsages(session, appId);\n onLog(`Deleting ${existing.length} existing answer${existing.length === 1 ? \"\" : \"s\"}`);\n for (const u of existing) await deleteAppDataUsage(session, u.id);\n\n let created = 0;\n for (const usage of usages) {\n // \"Not collected\" has no purposes but still needs one AppDataUsage, so\n // iterate over [null] — the same trick Fastlane uses.\n const purposes: Array<string | null> = usage.purposes?.length ? usage.purposes : [null];\n for (const purpose of purposes) {\n for (const protection of usage.data_protections) {\n onLog(protection === \"DATA_NOT_COLLECTED\"\n ? `Setting ${protection}`\n : `Setting ${usage.category} and ${purpose} to ${protection}`);\n await createAppDataUsage(session, { appId, category: usage.category ?? null, purpose, dataProtection: protection });\n created++;\n }\n }\n }\n\n if (skipPublish) {\n onLog(\"Skipping publish\");\n return { deleted: existing.length, created, published: false };\n }\n const state = await getAppDataUsagesPublishState(session, appId);\n await publishAppDataUsages(session, state.id);\n onLog(\"Published\");\n return { deleted: existing.length, created, published: true };\n}\n\n/** Catch the answers App Store Connect would refuse, before deleting what is there. */\nexport function validateUsages(usages: AppPrivacyUsage[]): void {\n if (!Array.isArray(usages) || usages.length === 0) throw new Error(\"No privacy usages given.\");\n const notCollected = usages.some((u) => u.data_protections?.includes(\"DATA_NOT_COLLECTED\"));\n if (notCollected && usages.length > 1) {\n throw new Error(\"DATA_NOT_COLLECTED must be the only entry: an app cannot both collect nothing and collect something.\");\n }\n const known = (list: readonly string[], v: string, what: string) => {\n if (!list.includes(v)) throw new Error(`\"${v}\" is not an App Store Connect ${what}. Use one of: ${list.join(\", \")}.`);\n };\n for (const u of usages) {\n if (!u.data_protections?.length) throw new Error(`${u.category ?? \"An entry\"} has no data_protections.`);\n // Checked here, before anything is deleted: App Store Connect refuses an\n // unknown id only when that one answer is created, halfway through.\n if (u.category) known(DATA_USAGE_CATEGORIES, u.category, \"data category\");\n for (const p of u.purposes ?? []) known(DATA_USAGE_PURPOSES, p, \"purpose\");\n for (const d of u.data_protections) known(DATA_PROTECTIONS, d, \"data protection\");\n if (u.data_protections.includes(\"DATA_NOT_COLLECTED\")) continue;\n if (!u.category) throw new Error(\"Every collected entry needs a category.\");\n if (!u.purposes?.length) throw new Error(`${u.category} needs at least one purpose.`);\n const linked = u.data_protections.includes(\"DATA_LINKED_TO_YOU\");\n const unlinked = u.data_protections.includes(\"DATA_NOT_LINKED_TO_YOU\");\n if (linked && unlinked) throw new Error(`${u.category} cannot be both linked and not linked to the user.`);\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/client/providers.ts","../../src/privacy/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * App Store Connect \"providers\": the teams an Apple ID belongs to, as App\n * Store Connect sees them. A web session works inside one provider at a time\n * — whichever the person used last — and everything iris creates (API keys,\n * app records) lands in that provider, not the developer-portal team the\n * portal calls were made for. Spaceship's `select_team` is the same switch.\n */\nimport type { AppleSession } from \"./apple-session.js\";\n\nconst OLYMPUS_SESSION = \"https://appstoreconnect.apple.com/olympus/v1/session\";\n\nexport interface AscProvider {\n providerId: number;\n name: string;\n}\n\nexport function cookieHeader(session: AppleSession): string {\n return Object.entries(session.cookies).map(([k, v]) => `${k}=${v}`).join(\"; \");\n}\n\nexport function absorbCookies(session: AppleSession, res: Response): void {\n for (const raw of res.headers.getSetCookie?.() ?? []) {\n const m = raw.match(/^([^=]+)=([^;]*)/);\n if (m) session.cookies[m[1]] = m[2];\n }\n}\n\n/** The provider the session is in now, and every provider it could switch to. */\nexport async function listProviders(session: AppleSession): Promise<{ current: AscProvider | null; providers: AscProvider[] }> {\n const res = await fetch(OLYMPUS_SESSION, { headers: { Cookie: cookieHeader(session), Accept: \"application/json\" } });\n absorbCookies(session, res);\n const info: any = await res.json().catch(() => null);\n const pick = (p: any): AscProvider | null =>\n p?.providerId != null ? { providerId: Number(p.providerId), name: String(p.name ?? p.providerId) } : null;\n const providers = ((info?.availableProviders ?? []) as any[]).map(pick).filter((p): p is AscProvider => !!p);\n return { current: pick(info?.provider), providers };\n}\n\n/** Move the session into another provider. True when Apple accepted it. */\nexport async function switchProvider(session: AppleSession, providerId: number): Promise<boolean> {\n const res = await fetch(OLYMPUS_SESSION, {\n method: \"POST\",\n headers: { Cookie: cookieHeader(session), \"Content-Type\": \"application/json\", Accept: \"application/json\" },\n body: JSON.stringify({ provider: { providerId } }),\n });\n absorbCookies(session, res);\n if (res.ok) session.teamId = String(providerId);\n return res.ok;\n}\n","/**\n * App Privacy details (\"nutrition labels\") for an app in App Store Connect.\n * 1:1 port of Fastlane's `upload_app_privacy_details_to_app_store` action and\n * Spaceship's AppDataUsage / AppDataUsagesPublishState models.\n *\n * The public App Store Connect API has no endpoint for privacy details — an\n * API key cannot set them. Fastlane goes through the iris API that App Store\n * Connect's own web UI uses, authenticated with an Apple ID session, and so\n * does this: pass the AppleSession from `loginWithAppleId` / the App Release\n * sign-in.\n *\n * Usages use Fastlane's JSON format, so an existing `app_privacy_details.json`\n * works unchanged:\n *\n * [\n * { \"category\": \"EMAIL_ADDRESS\", \"purposes\": [\"APP_FUNCTIONALITY\"], \"data_protections\": [\"DATA_LINKED_TO_YOU\"] },\n * { \"data_protections\": [\"DATA_NOT_COLLECTED\"] } // an app that collects nothing\n * ]\n *\n * As in Fastlane, the upload REPLACES everything: existing usages are deleted\n * first, then the new ones are created, then the answers are published.\n */\n\nimport type { AppleSession } from \"../client/apple-session.js\";\nimport { absorbCookies, cookieHeader, listProviders, switchProvider } from \"../client/providers.js\";\n\nconst IRIS_BASE = \"https://appstoreconnect.apple.com/iris/v1\";\n\n/** Every category App Store Connect accepts. Anything else is refused before existing answers are deleted. */\nexport const DATA_USAGE_CATEGORIES = [\n \"PAYMENT_INFORMATION\", \"CREDIT_AND_FRAUD\", \"OTHER_FINANCIAL_INFO\",\n \"PRECISE_LOCATION\", \"COARSE_LOCATION\", \"SENSITIVE_INFO\",\n \"PHYSICAL_ADDRESS\", \"EMAIL_ADDRESS\", \"NAME\", \"PHONE_NUMBER\", \"OTHER_CONTACT_INFO\",\n \"CONTACTS\", \"EMAILS_OR_TEXT_MESSAGES\", \"PHOTOS_OR_VIDEOS\", \"AUDIO\", \"GAMEPLAY_CONTENT\",\n \"CUSTOMER_SUPPORT\", \"OTHER_USER_CONTENT\", \"BROWSING_HISTORY\", \"SEARCH_HISTORY\",\n \"USER_ID\", \"DEVICE_ID\", \"PURCHASE_HISTORY\", \"PRODUCT_INTERACTION\", \"ADVERTISING_DATA\",\n \"OTHER_USAGE_DATA\", \"CRASH_DATA\", \"PERFORMANCE_DATA\", \"OTHER_DIAGNOSTIC_DATA\",\n \"OTHER_DATA\", \"HEALTH\", \"FITNESS\",\n] as const;\nexport const DATA_USAGE_PURPOSES = [\n \"THIRD_PARTY_ADVERTISING\", \"DEVELOPERS_ADVERTISING\", \"ANALYTICS\",\n \"PRODUCT_PERSONALIZATION\", \"APP_FUNCTIONALITY\", \"OTHER_PURPOSES\",\n] as const;\nexport const DATA_PROTECTIONS = [\n \"DATA_USED_TO_TRACK_YOU\", \"DATA_LINKED_TO_YOU\", \"DATA_NOT_LINKED_TO_YOU\", \"DATA_NOT_COLLECTED\",\n] as const;\n\nexport type DataUsageCategory =\n | \"PAYMENT_INFORMATION\" | \"CREDIT_AND_FRAUD\" | \"OTHER_FINANCIAL_INFO\"\n | \"PRECISE_LOCATION\" | \"COARSE_LOCATION\" | \"SENSITIVE_INFO\"\n | \"PHYSICAL_ADDRESS\" | \"EMAIL_ADDRESS\" | \"NAME\" | \"PHONE_NUMBER\" | \"OTHER_CONTACT_INFO\"\n | \"CONTACTS\" | \"EMAILS_OR_TEXT_MESSAGES\" | \"PHOTOS_OR_VIDEOS\" | \"AUDIO\" | \"GAMEPLAY_CONTENT\"\n | \"CUSTOMER_SUPPORT\" | \"OTHER_USER_CONTENT\" | \"BROWSING_HISTORY\" | \"SEARCH_HISTORY\"\n | \"USER_ID\" | \"DEVICE_ID\" | \"PURCHASE_HISTORY\" | \"PRODUCT_INTERACTION\" | \"ADVERTISING_DATA\"\n | \"OTHER_USAGE_DATA\" | \"CRASH_DATA\" | \"PERFORMANCE_DATA\" | \"OTHER_DIAGNOSTIC_DATA\"\n | \"OTHER_DATA\" | \"HEALTH\" | \"FITNESS\";\n\nexport type DataUsagePurpose =\n | \"THIRD_PARTY_ADVERTISING\" | \"DEVELOPERS_ADVERTISING\" | \"ANALYTICS\"\n | \"PRODUCT_PERSONALIZATION\" | \"APP_FUNCTIONALITY\" | \"OTHER_PURPOSES\";\n\nexport type DataProtection =\n | \"DATA_USED_TO_TRACK_YOU\" | \"DATA_LINKED_TO_YOU\" | \"DATA_NOT_LINKED_TO_YOU\" | \"DATA_NOT_COLLECTED\";\n\n/** One entry of Fastlane's app_privacy_details.json. */\nexport interface AppPrivacyUsage {\n category?: DataUsageCategory;\n purposes?: DataUsagePurpose[];\n data_protections: DataProtection[];\n}\n\nexport interface UploadAppPrivacyOptions {\n session: AppleSession;\n /** App Store Connect app id (the numeric Apple ID). */\n appId: string;\n usages: AppPrivacyUsage[];\n /** Leave the answers saved but unpublished (Fastlane's skip_publish). */\n skipPublish?: boolean;\n onLog?: (msg: string) => void;\n}\n\nexport interface UploadAppPrivacyResult {\n deleted: number;\n created: number;\n published: boolean;\n}\n\ninterface IrisResponse { status: number; body: any; text: string }\n\nasync function iris(session: AppleSession, method: string, path: string, body?: unknown): Promise<IrisResponse> {\n const res = await fetch(path.startsWith(\"http\") ? path : `${IRIS_BASE}${path}`, {\n method,\n headers: {\n Cookie: cookieHeader(session),\n Accept: \"application/vnd.api+json, application/json\",\n \"Content-Type\": \"application/vnd.api+json\",\n \"X-Requested-With\": \"XMLHttpRequest\",\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n absorbCookies(session, res);\n const text = await res.text();\n let parsed: any = null;\n try { parsed = text ? JSON.parse(text) : null; } catch { /* not JSON */ }\n return { status: res.status, body: parsed, text };\n}\n\n\nfunction fail(what: string, r: IrisResponse): never {\n const detail = r.body?.errors?.map((e: any) => e.detail ?? e.title).join(\"; \") || r.text.slice(0, 300);\n throw new Error(`${what} failed (HTTP ${r.status}): ${detail}`);\n}\n\n/**\n * Point the session at the App Store Connect provider (team) that owns the app.\n *\n * An Apple ID in several teams signs in to whichever one it used last, and\n * iris answers 404 for another team's app. Spaceship's `select_team` does the\n * same switch: POST the provider id to the olympus session.\n */\nexport async function selectProviderForApp(session: AppleSession, appId: string, onLog?: (m: string) => void): Promise<void> {\n const owns = async () => (await iris(session, \"GET\", `/apps/${appId}?fields[apps]=name`)).status === 200;\n if (await owns()) return;\n\n const { providers } = await listProviders(session);\n for (const p of providers) {\n if ((await switchProvider(session, p.providerId)) && (await owns())) {\n onLog?.(`Switched to team \"${p.name}\"`);\n return;\n }\n }\n throw new Error(`None of this Apple ID's ${providers.length} teams can see app ${appId}.`);\n}\n\n/** Existing privacy answers for an app. */\nexport async function listAppDataUsages(session: AppleSession, appId: string): Promise<Array<{ id: string }>> {\n const all: Array<{ id: string }> = [];\n let next: string | null = `/apps/${appId}/dataUsages?include=category,grouping,purpose,dataProtection&limit=500`;\n while (next) {\n const r = await iris(session, \"GET\", next);\n if (r.status !== 200) fail(\"List app data usages\", r);\n all.push(...(r.body?.data ?? []).map((d: any) => ({ id: d.id })));\n next = r.body?.links?.next ?? null;\n }\n return all;\n}\n\n/** Spaceship AppDataUsage.create — relationships are sent only when given. */\nexport async function createAppDataUsage(\n session: AppleSession,\n input: { appId: string; category?: string | null; purpose?: string | null; dataProtection: string },\n): Promise<string> {\n const relationships: Record<string, unknown> = { app: { data: { type: \"apps\", id: input.appId } } };\n if (input.category) relationships.category = { data: { type: \"appDataUsageCategories\", id: input.category } };\n if (input.purpose) relationships.purpose = { data: { type: \"appDataUsagePurposes\", id: input.purpose } };\n relationships.dataProtection = { data: { type: \"appDataUsageDataProtections\", id: input.dataProtection } };\n const r = await iris(session, \"POST\", \"/appDataUsages\", { data: { type: \"appDataUsages\", relationships } });\n if (r.status !== 201 && r.status !== 200) fail(`Create ${input.category ?? \"\"} ${input.purpose ?? \"\"} ${input.dataProtection}`.replace(/\\s+/g, \" \"), r);\n return r.body?.data?.id;\n}\n\nexport async function deleteAppDataUsage(session: AppleSession, id: string): Promise<void> {\n const r = await iris(session, \"DELETE\", `/appDataUsages/${id}`);\n if (r.status !== 204 && r.status !== 200) fail(`Delete app data usage ${id}`, r);\n}\n\nexport async function getAppDataUsagesPublishState(session: AppleSession, appId: string): Promise<{ id: string; published: boolean }> {\n const r = await iris(session, \"GET\", `/apps/${appId}/dataUsagePublishState`);\n if (r.status !== 200) fail(\"Read privacy publish state\", r);\n return { id: r.body.data.id, published: Boolean(r.body.data.attributes?.published) };\n}\n\nexport async function publishAppDataUsages(session: AppleSession, publishStateId: string): Promise<void> {\n const r = await iris(session, \"PATCH\", `/appDataUsagesPublishState/${publishStateId}`, {\n data: { type: \"appDataUsagesPublishState\", id: publishStateId, attributes: { published: true } },\n });\n if (r.status !== 200) fail(\"Publish privacy details\", r);\n}\n\n/** Fastlane's `upload_app_privacy_details_to_app_store`. Replaces all answers, then publishes. */\nexport async function uploadAppPrivacyDetails(opts: UploadAppPrivacyOptions): Promise<UploadAppPrivacyResult> {\n const { session, appId, usages, skipPublish, onLog = () => {} } = opts;\n validateUsages(usages);\n await selectProviderForApp(session, appId, onLog);\n\n const existing = await listAppDataUsages(session, appId);\n onLog(`Deleting ${existing.length} existing answer${existing.length === 1 ? \"\" : \"s\"}`);\n for (const u of existing) await deleteAppDataUsage(session, u.id);\n\n let created = 0;\n for (const usage of usages) {\n // \"Not collected\" has no purposes but still needs one AppDataUsage, so\n // iterate over [null] — the same trick Fastlane uses.\n const purposes: Array<string | null> = usage.purposes?.length ? usage.purposes : [null];\n for (const purpose of purposes) {\n for (const protection of usage.data_protections) {\n onLog(protection === \"DATA_NOT_COLLECTED\"\n ? `Setting ${protection}`\n : `Setting ${usage.category} and ${purpose} to ${protection}`);\n await createAppDataUsage(session, { appId, category: usage.category ?? null, purpose, dataProtection: protection });\n created++;\n }\n }\n }\n\n if (skipPublish) {\n onLog(\"Skipping publish\");\n return { deleted: existing.length, created, published: false };\n }\n const state = await getAppDataUsagesPublishState(session, appId);\n await publishAppDataUsages(session, state.id);\n onLog(\"Published\");\n return { deleted: existing.length, created, published: true };\n}\n\n/** Catch the answers App Store Connect would refuse, before deleting what is there. */\nexport function validateUsages(usages: AppPrivacyUsage[]): void {\n if (!Array.isArray(usages) || usages.length === 0) throw new Error(\"No privacy usages given.\");\n const notCollected = usages.some((u) => u.data_protections?.includes(\"DATA_NOT_COLLECTED\"));\n if (notCollected && usages.length > 1) {\n throw new Error(\"DATA_NOT_COLLECTED must be the only entry: an app cannot both collect nothing and collect something.\");\n }\n const known = (list: readonly string[], v: string, what: string) => {\n if (!list.includes(v)) throw new Error(`\"${v}\" is not an App Store Connect ${what}. Use one of: ${list.join(\", \")}.`);\n };\n for (const u of usages) {\n if (!u.data_protections?.length) throw new Error(`${u.category ?? \"An entry\"} has no data_protections.`);\n // Checked here, before anything is deleted: App Store Connect refuses an\n // unknown id only when that one answer is created, halfway through.\n if (u.category) known(DATA_USAGE_CATEGORIES, u.category, \"data category\");\n for (const p of u.purposes ?? []) known(DATA_USAGE_PURPOSES, p, \"purpose\");\n for (const d of u.data_protections) known(DATA_PROTECTIONS, d, \"data protection\");\n if (u.data_protections.includes(\"DATA_NOT_COLLECTED\")) continue;\n if (!u.category) throw new Error(\"Every collected entry needs a category.\");\n if (!u.purposes?.length) throw new Error(`${u.category} needs at least one purpose.`);\n const linked = u.data_protections.includes(\"DATA_LINKED_TO_YOU\");\n const unlinked = u.data_protections.includes(\"DATA_NOT_LINKED_TO_YOU\");\n if (linked && unlinked) throw new Error(`${u.category} cannot be both linked and not linked to the user.`);\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import '../index-CpGV1f0L.cjs';
2
- import '../enums-yXNVh3UI.cjs';
3
- export { P as ProduceOptions, S as SERVICE_NAME_TO_CAPABILITY, a as addCapability, d as associateAppGroups, b as buildCapabilitySettings, f as createApp, e as enableServices, l as listCapabilities, r as registerBundleId, c as removeCapability } from '../index-BbVQzSV1.cjs';
4
- import '../apple-session-jUzBrql5.cjs';
1
+ import '../index-HWWl6HEL.cjs';
2
+ import '../enums-BlpayMTx.cjs';
3
+ export { P as ProduceOptions, S as SERVICE_NAME_TO_CAPABILITY, a as addCapability, b as associateAppGroups, c as buildCapabilitySettings, d as createApp, e as enableServices, l as listCapabilities, r as registerBundleId, f as removeCapability } from '../index-DRjXV9ej.cjs';
4
+ import '../apple-session-D6x7Jo3D.cjs';
@@ -1,4 +1,4 @@
1
- import '../index-CemR3UI9.js';
2
- import '../enums-yXNVh3UI.js';
3
- export { P as ProduceOptions, S as SERVICE_NAME_TO_CAPABILITY, a as addCapability, d as associateAppGroups, b as buildCapabilitySettings, f as createApp, e as enableServices, l as listCapabilities, r as registerBundleId, c as removeCapability } from '../index-C-EEYXSE.js';
4
- import '../apple-session-jUzBrql5.js';
1
+ import '../index-SyCMBpNN.js';
2
+ import '../enums-BlpayMTx.js';
3
+ export { P as ProduceOptions, S as SERVICE_NAME_TO_CAPABILITY, a as addCapability, b as associateAppGroups, c as buildCapabilitySettings, d as createApp, e as enableServices, l as listCapabilities, r as registerBundleId, f as removeCapability } from '../index-C8L03MBu.js';
4
+ import '../apple-session-D6x7Jo3D.js';
@@ -1,8 +1,37 @@
1
1
  'use strict';
2
2
 
3
+ // src/client/providers.ts
4
+ var OLYMPUS_SESSION = "https://appstoreconnect.apple.com/olympus/v1/session";
5
+ function cookieHeader(session) {
6
+ return Object.entries(session.cookies).map(([k, v]) => `${k}=${v}`).join("; ");
7
+ }
8
+ function absorbCookies(session, res) {
9
+ for (const raw of res.headers.getSetCookie?.() ?? []) {
10
+ const m = raw.match(/^([^=]+)=([^;]*)/);
11
+ if (m) session.cookies[m[1]] = m[2];
12
+ }
13
+ }
14
+ async function listProviders(session) {
15
+ const res = await fetch(OLYMPUS_SESSION, { headers: { Cookie: cookieHeader(session), Accept: "application/json" } });
16
+ absorbCookies(session, res);
17
+ const info = await res.json().catch(() => null);
18
+ const pick = (p) => p?.providerId != null ? { providerId: Number(p.providerId), name: String(p.name ?? p.providerId) } : null;
19
+ const providers = (info?.availableProviders ?? []).map(pick).filter((p) => !!p);
20
+ return { current: pick(info?.provider), providers };
21
+ }
22
+ async function switchProvider(session, providerId) {
23
+ const res = await fetch(OLYMPUS_SESSION, {
24
+ method: "POST",
25
+ headers: { Cookie: cookieHeader(session), "Content-Type": "application/json", Accept: "application/json" },
26
+ body: JSON.stringify({ provider: { providerId } })
27
+ });
28
+ absorbCookies(session, res);
29
+ if (res.ok) session.teamId = String(providerId);
30
+ return res.ok;
31
+ }
32
+
3
33
  // src/privacy/index.ts
4
34
  var IRIS_BASE = "https://appstoreconnect.apple.com/iris/v1";
5
- var OLYMPUS_SESSION = "https://appstoreconnect.apple.com/olympus/v1/session";
6
35
  async function iris(session, method, path, body) {
7
36
  const res = await fetch(path.startsWith("http") ? path : `${IRIS_BASE}${path}`, {
8
37
  method,
@@ -23,32 +52,13 @@ async function iris(session, method, path, body) {
23
52
  }
24
53
  return { status: res.status, body: parsed, text };
25
54
  }
26
- function cookieHeader(session) {
27
- return Object.entries(session.cookies).map(([k, v]) => `${k}=${v}`).join("; ");
28
- }
29
- function absorbCookies(session, res) {
30
- for (const raw of res.headers.getSetCookie?.() ?? []) {
31
- const m = raw.match(/^([^=]+)=([^;]*)/);
32
- if (m) session.cookies[m[1]] = m[2];
33
- }
34
- }
35
55
  async function selectProviderForApp(session, appId, onLog) {
36
56
  const owns = async () => (await iris(session, "GET", `/apps/${appId}?fields[apps]=name`)).status === 200;
37
57
  if (await owns()) return;
38
- const res = await fetch(OLYMPUS_SESSION, { headers: { Cookie: cookieHeader(session), Accept: "application/json" } });
39
- absorbCookies(session, res);
40
- const info = await res.json().catch(() => null);
41
- const providers = info?.availableProviders ?? [];
58
+ const { providers } = await listProviders(session);
42
59
  for (const p of providers) {
43
- const sw = await fetch(OLYMPUS_SESSION, {
44
- method: "POST",
45
- headers: { Cookie: cookieHeader(session), "Content-Type": "application/json", Accept: "application/json" },
46
- body: JSON.stringify({ provider: { providerId: p.providerId } })
47
- });
48
- absorbCookies(session, sw);
49
- if (sw.ok && await owns()) {
60
+ if (await switchProvider(session, p.providerId) && await owns()) {
50
61
  onLog?.(`Switched to team "${p.name}"`);
51
- session.teamId = String(p.providerId);
52
62
  return;
53
63
  }
54
64
  }