primitive-admin 1.0.62 → 1.0.63
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.
- package/dist/src/commands/apps.js +5 -2
- package/dist/src/commands/apps.js.map +1 -1
- package/dist/src/commands/email-templates.js +3 -3
- package/dist/src/commands/email-templates.js.map +1 -1
- package/dist/src/commands/env.js +17 -1
- package/dist/src/commands/env.js.map +1 -1
- package/dist/src/commands/init.d.ts +15 -0
- package/dist/src/commands/init.js +158 -22
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/integrations.js +30 -14
- package/dist/src/commands/integrations.js.map +1 -1
- package/dist/src/commands/scripts.d.ts +10 -0
- package/dist/src/commands/scripts.js +137 -8
- package/dist/src/commands/scripts.js.map +1 -1
- package/dist/src/commands/sync.d.ts +1 -31
- package/dist/src/commands/sync.js +5 -79
- package/dist/src/commands/sync.js.map +1 -1
- package/dist/src/lib/env-resolver-core.d.ts +40 -0
- package/dist/src/lib/env-resolver-core.js +60 -0
- package/dist/src/lib/env-resolver-core.js.map +1 -1
- package/dist/src/lib/init-client-platforms.d.ts +14 -0
- package/dist/src/lib/init-client-platforms.js +71 -0
- package/dist/src/lib/init-client-platforms.js.map +1 -0
- package/dist/src/lib/init-email-redirect-uris.d.ts +37 -0
- package/dist/src/lib/init-email-redirect-uris.js +46 -0
- package/dist/src/lib/init-email-redirect-uris.js.map +1 -0
- package/dist/src/lib/init-ios-links.d.ts +40 -0
- package/dist/src/lib/init-ios-links.js +66 -1
- package/dist/src/lib/init-ios-links.js.map +1 -1
- package/dist/src/lib/integration-selector.d.ts +42 -0
- package/dist/src/lib/integration-selector.js +46 -0
- package/dist/src/lib/integration-selector.js.map +1 -0
- package/dist/src/lib/local-test-cases.d.ts +63 -0
- package/dist/src/lib/local-test-cases.js +135 -0
- package/dist/src/lib/local-test-cases.js.map +1 -0
- package/dist/src/lib/project-config.d.ts +8 -0
- package/dist/src/lib/project-config.js +17 -0
- package/dist/src/lib/project-config.js.map +1 -1
- package/dist/src/lib/test-case-file-names.d.ts +40 -0
- package/dist/src/lib/test-case-file-names.js +91 -0
- package/dist/src/lib/test-case-file-names.js.map +1 -0
- package/dist/src/lib/web-url.d.ts +40 -0
- package/dist/src/lib/web-url.js +76 -0
- package/dist/src/lib/web-url.js.map +1 -0
- package/package.json +1 -1
|
@@ -52,8 +52,46 @@ export interface CoreEnvironmentEntry {
|
|
|
52
52
|
apiUrl: string;
|
|
53
53
|
appId?: string;
|
|
54
54
|
appName?: string;
|
|
55
|
+
/**
|
|
56
|
+
* The app's web counterpart for this environment, as a normalized origin
|
|
57
|
+
* (#2982). Read through `normalizeWebOrigin`, so a value this reader carries
|
|
58
|
+
* is always an origin — see that function for why the typed read other
|
|
59
|
+
* fields get is not enough here.
|
|
60
|
+
*/
|
|
61
|
+
webUrl?: string;
|
|
55
62
|
description?: string;
|
|
56
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* The app's web counterpart as a normalized ORIGIN, or undefined when the
|
|
66
|
+
* value cannot be one (#2982).
|
|
67
|
+
*
|
|
68
|
+
* Unlike `appId`/`appName`, a typed read is not enough. This value is not
|
|
69
|
+
* merely carried: the Swift app points its emailed sign-in link at
|
|
70
|
+
* `<webUrl>/oauth/callback` and trusts incoming universal links from the same
|
|
71
|
+
* origin, and BOTH jobs need an origin —
|
|
72
|
+
*
|
|
73
|
+
* - https except loopback, the rule the server applies to every redirect URI
|
|
74
|
+
* (`src/auth/redirect-uri.ts`): an origin that cannot be allow-listed turns
|
|
75
|
+
* every sign-in request into a 400, and a plain-http link would carry the
|
|
76
|
+
* magic token in clear;
|
|
77
|
+
* - no path, query or fragment: the web client serves its callback on its own
|
|
78
|
+
* origin plus `/oauth/callback`, which is also the exact path the
|
|
79
|
+
* `apple-app-site-association` component claims;
|
|
80
|
+
* - no credentials, which have no business in a link that goes out by email.
|
|
81
|
+
*
|
|
82
|
+
* `primitive env add --web-url` and the project-config validation reject those
|
|
83
|
+
* shapes with a field-named error, but neither is on the path from a
|
|
84
|
+
* hand-edited `.primitive/config.json` to an Xcode build: the Swift template's
|
|
85
|
+
* pre-build script reads the file directly. So every reader that feeds
|
|
86
|
+
* `primitive.json` applies the contract, and a value that misses it is read as
|
|
87
|
+
* "this environment has no web counterpart" — code-only email, no trusted
|
|
88
|
+
* origin, nothing silently pointed at the wrong URL.
|
|
89
|
+
*
|
|
90
|
+
* The message-producing twin of this rule lives in `cli/src/lib/web-url.ts`;
|
|
91
|
+
* this file cannot import it (see COPYABILITY above), and a test pins that the
|
|
92
|
+
* two agree.
|
|
93
|
+
*/
|
|
94
|
+
export declare function normalizeWebOrigin(value: unknown): string | undefined;
|
|
57
95
|
export interface CoreProjectConfig {
|
|
58
96
|
version: number;
|
|
59
97
|
defaultEnvironment?: string;
|
|
@@ -68,6 +106,8 @@ export interface ResolvedPrimitiveEnv {
|
|
|
68
106
|
wsUrl: string;
|
|
69
107
|
appId?: string;
|
|
70
108
|
appName?: string;
|
|
109
|
+
/** The app's web counterpart for the SELECTED environment, if it has one. */
|
|
110
|
+
webUrl?: string;
|
|
71
111
|
description?: string;
|
|
72
112
|
source: PrimitiveEnvSource;
|
|
73
113
|
configPath: string;
|
|
@@ -50,6 +50,64 @@ export class PrimitiveEnvError extends Error {
|
|
|
50
50
|
this.path = path;
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* The app's web counterpart as a normalized ORIGIN, or undefined when the
|
|
55
|
+
* value cannot be one (#2982).
|
|
56
|
+
*
|
|
57
|
+
* Unlike `appId`/`appName`, a typed read is not enough. This value is not
|
|
58
|
+
* merely carried: the Swift app points its emailed sign-in link at
|
|
59
|
+
* `<webUrl>/oauth/callback` and trusts incoming universal links from the same
|
|
60
|
+
* origin, and BOTH jobs need an origin —
|
|
61
|
+
*
|
|
62
|
+
* - https except loopback, the rule the server applies to every redirect URI
|
|
63
|
+
* (`src/auth/redirect-uri.ts`): an origin that cannot be allow-listed turns
|
|
64
|
+
* every sign-in request into a 400, and a plain-http link would carry the
|
|
65
|
+
* magic token in clear;
|
|
66
|
+
* - no path, query or fragment: the web client serves its callback on its own
|
|
67
|
+
* origin plus `/oauth/callback`, which is also the exact path the
|
|
68
|
+
* `apple-app-site-association` component claims;
|
|
69
|
+
* - no credentials, which have no business in a link that goes out by email.
|
|
70
|
+
*
|
|
71
|
+
* `primitive env add --web-url` and the project-config validation reject those
|
|
72
|
+
* shapes with a field-named error, but neither is on the path from a
|
|
73
|
+
* hand-edited `.primitive/config.json` to an Xcode build: the Swift template's
|
|
74
|
+
* pre-build script reads the file directly. So every reader that feeds
|
|
75
|
+
* `primitive.json` applies the contract, and a value that misses it is read as
|
|
76
|
+
* "this environment has no web counterpart" — code-only email, no trusted
|
|
77
|
+
* origin, nothing silently pointed at the wrong URL.
|
|
78
|
+
*
|
|
79
|
+
* The message-producing twin of this rule lives in `cli/src/lib/web-url.ts`;
|
|
80
|
+
* this file cannot import it (see COPYABILITY above), and a test pins that the
|
|
81
|
+
* two agree.
|
|
82
|
+
*/
|
|
83
|
+
export function normalizeWebOrigin(value) {
|
|
84
|
+
if (typeof value !== "string")
|
|
85
|
+
return undefined;
|
|
86
|
+
const trimmed = value.trim();
|
|
87
|
+
if (!trimmed)
|
|
88
|
+
return undefined;
|
|
89
|
+
let url;
|
|
90
|
+
try {
|
|
91
|
+
url = new URL(trimmed);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
if (url.protocol !== "https:" && url.protocol !== "http:")
|
|
97
|
+
return undefined;
|
|
98
|
+
if (url.protocol === "http:" &&
|
|
99
|
+
url.hostname !== "localhost" &&
|
|
100
|
+
url.hostname !== "127.0.0.1") {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
if (url.username || url.password)
|
|
104
|
+
return undefined;
|
|
105
|
+
if (url.pathname !== "/" && url.pathname !== "")
|
|
106
|
+
return undefined;
|
|
107
|
+
if (url.search || url.hash)
|
|
108
|
+
return undefined;
|
|
109
|
+
return url.origin;
|
|
110
|
+
}
|
|
53
111
|
/**
|
|
54
112
|
* Derives the WebSocket URL from the API URL. Every apiUrl/wsUrl pair in
|
|
55
113
|
* practice is the same host with the scheme swapped, so it is derived rather
|
|
@@ -149,6 +207,7 @@ export function readCoreProjectConfig(configPath) {
|
|
|
149
207
|
apiUrl: e.apiUrl.replace(/\/$/, ""),
|
|
150
208
|
appId: typeof e.appId === "string" ? e.appId : undefined,
|
|
151
209
|
appName: typeof e.appName === "string" ? e.appName : undefined,
|
|
210
|
+
webUrl: normalizeWebOrigin(e.webUrl),
|
|
152
211
|
description: typeof e.description === "string" ? e.description : undefined,
|
|
153
212
|
};
|
|
154
213
|
}
|
|
@@ -255,6 +314,7 @@ export function resolvePrimitiveEnv(options = {}) {
|
|
|
255
314
|
wsUrl: deriveWsUrl(entry.apiUrl),
|
|
256
315
|
appId: entry.appId,
|
|
257
316
|
appName: entry.appName,
|
|
317
|
+
webUrl: entry.webUrl,
|
|
258
318
|
description: entry.description,
|
|
259
319
|
source,
|
|
260
320
|
configPath,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env-resolver-core.js","sourceRoot":"","sources":["../../../src/lib/env-resolver-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7D,wEAAwE;AACxE,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAC1C,4EAA4E;AAC5E,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC;AAE/C,MAAM,CAAC,MAAM,kBAAkB,GAAG,YAAY,CAAC;AAC/C,MAAM,CAAC,MAAM,uBAAuB,GAAG,aAAa,CAAC;AACrD,MAAM,CAAC,MAAM,oBAAoB,GAAG,YAAY,CAAC;AACjD,MAAM,CAAC,MAAM,2BAA2B,GAAG,wBAAwB,CAAC;AACpE,MAAM,CAAC,MAAM,wBAAwB,GAAG,uBAAuB,CAAC;AAehE,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACjC,IAAI,CAAwB;IAC5B,IAAI,CAAU;IAEvB,YAAY,IAA2B,EAAE,OAAe,EAAE,IAAa;QACrE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;
|
|
1
|
+
{"version":3,"file":"env-resolver-core.js","sourceRoot":"","sources":["../../../src/lib/env-resolver-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7D,wEAAwE;AACxE,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAC1C,4EAA4E;AAC5E,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC;AAE/C,MAAM,CAAC,MAAM,kBAAkB,GAAG,YAAY,CAAC;AAC/C,MAAM,CAAC,MAAM,uBAAuB,GAAG,aAAa,CAAC;AACrD,MAAM,CAAC,MAAM,oBAAoB,GAAG,YAAY,CAAC;AACjD,MAAM,CAAC,MAAM,2BAA2B,GAAG,wBAAwB,CAAC;AACpE,MAAM,CAAC,MAAM,wBAAwB,GAAG,uBAAuB,CAAC;AAehE,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACjC,IAAI,CAAwB;IAC5B,IAAI,CAAU;IAEvB,YAAY,IAA2B,EAAE,OAAe,EAAE,IAAa;QACrE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAgBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAChD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO;QAAE,OAAO,SAAS,CAAC;IAC5E,IACE,GAAG,CAAC,QAAQ,KAAK,OAAO;QACxB,GAAG,CAAC,QAAQ,KAAK,WAAW;QAC5B,GAAG,CAAC,QAAQ,KAAK,WAAW,EAC5B,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAC;IACnD,IAAI,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAClE,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC7C,OAAO,GAAG,CAAC,MAAM,CAAC;AACpB,CAAC;AA2CD;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,IAAI,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IACrF,IAAI,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAClF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACrC,UAAsE,EAAE;IAExE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACvC,MAAM,QAAQ,GAAG,GAAG,CAAC,wBAAwB,CAAC;IAC9C,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;QACjC,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5C,CAAC;IAED,IAAI,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACpD,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,CAAC,CAAC;QAC7E,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;QAC5C,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QAChC,IAAI,MAAM,KAAK,OAAO;YAAE,OAAO,IAAI,CAAC;QACpC,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,UAAkB;IACzD,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,OAAO,QAAQ,CAAC,GAAG,CAAC,KAAK,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AACnE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CAAC,UAAkB;IAC5D,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,oBAAoB,CAAC,CAAC;AACzD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,UAAkB;IACtD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,iBAAiB,CACzB,gBAAgB,EAChB,MAAM,2BAA2B,aAAa,UAAU,uCAAuC,EAC/F,UAAU,CACX,CAAC;IACJ,CAAC;IAED,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,MAAM,IAAI,iBAAiB,CACzB,kBAAkB,EAClB,kBAAkB,2BAA2B,KAAK,UAAU,MAAM,GAAG,CAAC,OAAO,EAAE,EAC/E,UAAU,CACX,CAAC;IACJ,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,MAAM,IAAI,iBAAiB,CACzB,kBAAkB,EAClB,mBAAmB,2BAA2B,KAAK,UAAU,MAAM,GAAG,CAAC,OAAO,EAAE,EAChF,UAAU,CACX,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnE,MAAM,IAAI,iBAAiB,CACzB,kBAAkB,EAClB,GAAG,2BAA2B,KAAK,UAAU,gDAAgD,EAC7F,UAAU,CACX,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,MAAiC,CAAC;IAE9C,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,iBAAiB,CACzB,kBAAkB,EAClB,GAAG,2BAA2B,KAAK,UAAU,gDAAgD,EAC7F,UAAU,CACX,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,CAAC,OAAO,KAAK,wBAAwB,EAAE,CAAC;QAC7C,MAAM,IAAI,iBAAiB,CACzB,qBAAqB,EACrB,GAAG,2BAA2B,KAAK,UAAU,iBAAiB,GAAG,CAAC,OAAO,uCAAuC,wBAAwB,GAAG,EAC3I,UAAU,CACX,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,YAAY,IAAI,OAAO,GAAG,CAAC,YAAY,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;QACjG,MAAM,IAAI,iBAAiB,CACzB,kBAAkB,EAClB,GAAG,2BAA2B,KAAK,UAAU,8CAA8C,EAC3F,UAAU,CACX,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAyC,EAAE,CAAC;IAC9D,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,YAAuC,CAAC,EAAE,CAAC;QACxF,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAChE,MAAM,IAAI,iBAAiB,CACzB,kBAAkB,EAClB,gBAAgB,IAAI,0BAA0B,2BAA2B,KAAK,UAAU,IAAI,EAC5F,UAAU,CACX,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,GAAG,KAAgC,CAAC;QAC3C,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;YAC9C,MAAM,IAAI,iBAAiB,CACzB,kBAAkB,EAClB,gBAAgB,IAAI,8CAA8C,2BAA2B,KAAK,UAAU,IAAI,EAChH,UAAU,CACX,CAAC;QACJ,CAAC;QACD,YAAY,CAAC,IAAI,CAAC,GAAG;YACnB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;YACnC,KAAK,EAAE,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;YACxD,OAAO,EAAE,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;YAC9D,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC;YACpC,WAAW,EAAE,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;SAC3E,CAAC;IACJ,CAAC;IAED,OAAO;QACL,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,kBAAkB,EAChB,OAAO,GAAG,CAAC,kBAAkB,KAAK,QAAQ,IAAI,GAAG,CAAC,kBAAkB;YAClE,CAAC,CAAC,GAAG,CAAC,kBAAkB;YACxB,CAAC,CAAC,SAAS;QACf,YAAY;KACb,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,UAAkB;IACnD,MAAM,IAAI,GAAG,2BAA2B,CAAC,UAAU,CAAC,CAAC;IACrD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAEnC,MAAM,OAAO,GAAG,CAAC,MAAc,EAAS,EAAE;QACxC,MAAM,IAAI,iBAAiB,CACzB,qBAAqB,EACrB,GAAG,wBAAwB,KAAK,IAAI,oBAAoB,MAAM,yDAAyD,EACvH,IAAI,CACL,CAAC;IACJ,CAAC,CAAC;IAEF,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IACnD,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IACD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnE,OAAO,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAC3C,CAAC;IACD,MAAM,GAAG,GAAG,MAAiC,CAAC;IAC9C,MAAM,QAAQ,GAAG,GAAG,CAAC,mBAAmB,CAAC;IACzC,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAChF,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,OAAO,CAAC,wCAAwC,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAAyB,EACzB,OAKC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC;IAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU;QAC9B,CAAC,CAAC,GAAG,2BAA2B,KAAK,OAAO,CAAC,UAAU,GAAG;QAC1D,CAAC,CAAC,2BAA2B,CAAC;IAEhC,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,MAA0B,EAAE,MAAc,EAAE,EAAE;QAChF,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,iBAAiB,CACzB,qBAAqB,EACrB,gBAAgB,IAAI,uBAAuB,KAAK,cAAc,MAAM,iBAAiB,IAAI,EAAE,EAC3F,OAAO,CAAC,UAAU,CACnB,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,CAAC,CAAC;IAEF,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;QAC5B,OAAO,YAAY,CAAC,OAAO,CAAC,eAAe,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QACvB,OAAO,YAAY,CAAC,OAAO,CAAC,UAAU,EAAE,SAAS,EAAE,mBAAmB,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,OAAO,YAAY,CAAC,OAAO,CAAC,cAAc,EAAE,OAAO,EAAE,MAAM,wBAAwB,EAAE,CAAC,CAAC;IACzF,CAAC;IACD,IAAI,MAAM,CAAC,kBAAkB,EAAE,CAAC;QAC9B,OAAO,YAAY,CAAC,MAAM,CAAC,kBAAkB,EAAE,SAAS,EAAE,yBAAyB,CAAC,CAAC;IACvF,CAAC;IACD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAChD,CAAC;IACD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,iBAAiB,CACzB,cAAc,EACd,GAAG,KAAK,mFAAmF,EAC3F,OAAO,CAAC,UAAU,CACnB,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,iBAAiB,CACzB,cAAc,EACd,wFAAwF,KAAK,yCAAyC,IAAI,EAAE,EAC5I,OAAO,CAAC,UAAU,CACnB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,UAA0B,EAAE;IAC9D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACvC,MAAM,UAAU,GACd,OAAO,CAAC,UAAU,IAAI,uBAAuB,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;IAE3E,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,iBAAiB,CACzB,gBAAgB,EAChB,MAAM,2BAA2B,aAAa,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,oHAAoH,CAC/L,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,qBAAqB,CAAC,UAAU,CAAC,CAAC;IACjD,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,qBAAqB,CAAC,MAAM,EAAE;QACrD,eAAe,EAAE,OAAO,CAAC,eAAe,IAAI,IAAI;QAChD,UAAU,EAAE,GAAG,CAAC,aAAa,IAAI,IAAI;QACrC,cAAc,EAAE,kBAAkB,CAAC,UAAU,CAAC;QAC9C,UAAU;KACX,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,OAAO,CAAC,YAAY,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACzC,MAAM,IAAI,iBAAiB,CACzB,gBAAgB,EAChB,gBAAgB,IAAI,QAAQ,2BAA2B,KAAK,UAAU,6EAA6E,IAAI,cAAc,KAAK,CAAC,MAAM,qCAAqC,EACtN,UAAU,CACX,CAAC;IACJ,CAAC;IAED,OAAO;QACL,IAAI;QACJ,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC;QAChC,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,MAAM;QACN,UAAU;QACV,cAAc,EAAE,2BAA2B,CAAC,UAAU,CAAC;QACvD,WAAW,EAAE,wBAAwB,CAAC,UAAU,CAAC;KAClD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Platform } from "./resolve-platform.js";
|
|
2
|
+
/**
|
|
3
|
+
* The platform of the client in `dir`, or null when `dir` is not a client.
|
|
4
|
+
* The ONE definition of the template signals — the AGENTS.md client listing
|
|
5
|
+
* and the both-platforms predicate read it, so they cannot drift.
|
|
6
|
+
*/
|
|
7
|
+
export declare function detectClientPlatform(dir: string): Platform | null;
|
|
8
|
+
/**
|
|
9
|
+
* Every platform already present under `projectRoot`, counting a client that
|
|
10
|
+
* IS the root. Deduplicated, in canonical order.
|
|
11
|
+
*/
|
|
12
|
+
export declare function discoverClientPlatforms(projectRoot: string): Platform[];
|
|
13
|
+
/** Whether the app ends up with an iOS client AND a web client. */
|
|
14
|
+
export declare function appHasBothPlatforms(planned: Platform[], discovered: Platform[]): boolean;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which client platforms an app HAS — the ones this run scaffolds plus the
|
|
3
|
+
* ones already in the repository (#2982).
|
|
4
|
+
*
|
|
5
|
+
* An app with both an iOS and a web client gets the universal-link wiring: the
|
|
6
|
+
* emailed sign-in link becomes the web deployment's https callback, which
|
|
7
|
+
* opens the installed app and still signs in from any browser. So "does this
|
|
8
|
+
* app have both?" decides whether init seeds a `webUrl` and prints the
|
|
9
|
+
* activation checklist.
|
|
10
|
+
*
|
|
11
|
+
* The existing clients are found by the signals the templates ship — a Swift
|
|
12
|
+
* package or Xcode project, a Vite project — so a `functions/` directory with
|
|
13
|
+
* a `package.json` is not mistaken for a client. They are looked for in child
|
|
14
|
+
* directories AND at the project root: `primitive init` still produces the
|
|
15
|
+
* flat single-client layout where the client IS the repository root, and
|
|
16
|
+
* adding the second platform to such a repository is exactly the case this
|
|
17
|
+
* feature exists for (DSO-2982-013).
|
|
18
|
+
*/
|
|
19
|
+
import { existsSync, readdirSync } from "fs";
|
|
20
|
+
import { join } from "path";
|
|
21
|
+
/**
|
|
22
|
+
* The platform of the client in `dir`, or null when `dir` is not a client.
|
|
23
|
+
* The ONE definition of the template signals — the AGENTS.md client listing
|
|
24
|
+
* and the both-platforms predicate read it, so they cannot drift.
|
|
25
|
+
*/
|
|
26
|
+
export function detectClientPlatform(dir) {
|
|
27
|
+
let hasXcodeProject = false;
|
|
28
|
+
try {
|
|
29
|
+
hasXcodeProject = readdirSync(dir).some((name) => name.endsWith(".xcodeproj"));
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
if (existsSync(join(dir, "Package.swift")) || hasXcodeProject)
|
|
35
|
+
return "ios";
|
|
36
|
+
if (existsSync(join(dir, "package.json")) && existsSync(join(dir, "vite.config.ts"))) {
|
|
37
|
+
return "web";
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Every platform already present under `projectRoot`, counting a client that
|
|
43
|
+
* IS the root. Deduplicated, in canonical order.
|
|
44
|
+
*/
|
|
45
|
+
export function discoverClientPlatforms(projectRoot) {
|
|
46
|
+
const found = new Set();
|
|
47
|
+
const atRoot = detectClientPlatform(projectRoot);
|
|
48
|
+
if (atRoot)
|
|
49
|
+
found.add(atRoot);
|
|
50
|
+
let entries;
|
|
51
|
+
try {
|
|
52
|
+
entries = readdirSync(projectRoot, { withFileTypes: true });
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
entries = [];
|
|
56
|
+
}
|
|
57
|
+
for (const entry of entries) {
|
|
58
|
+
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
59
|
+
continue;
|
|
60
|
+
const platform = detectClientPlatform(join(projectRoot, entry.name));
|
|
61
|
+
if (platform)
|
|
62
|
+
found.add(platform);
|
|
63
|
+
}
|
|
64
|
+
return ["web", "ios"].filter((platform) => found.has(platform));
|
|
65
|
+
}
|
|
66
|
+
/** Whether the app ends up with an iOS client AND a web client. */
|
|
67
|
+
export function appHasBothPlatforms(planned, discovered) {
|
|
68
|
+
const platforms = new Set([...planned, ...discovered]);
|
|
69
|
+
return platforms.has("ios") && platforms.has("web");
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=init-client-platforms.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-client-platforms.js","sourceRoot":"","sources":["../../../src/lib/init-client-platforms.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,IAAI,CAAC;AAE7C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,IAAI,eAAe,GAAG,KAAK,CAAC;IAC5B,IAAI,CAAC;QACH,eAAe,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;IACjF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,IAAI,eAAe;QAAE,OAAO,KAAK,CAAC;IAC5E,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC;QACrF,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,WAAmB;IACzD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAY,CAAC;IAElC,MAAM,MAAM,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC;IACjD,IAAI,MAAM;QAAE,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAE9B,IAAI,OAAiB,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,GAAG,WAAW,CAAC,WAAW,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,EAAE,CAAC;IACf,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QACjE,MAAM,QAAQ,GAAG,oBAAoB,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QACrE,IAAI,QAAQ;YAAE,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;IAED,OAAQ,CAAC,KAAK,EAAE,KAAK,CAAW,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,mBAAmB,CACjC,OAAmB,EACnB,UAAsB;IAEtB,MAAM,SAAS,GAAG,IAAI,GAAG,CAAW,CAAC,GAAG,OAAO,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC;IACjE,OAAO,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether init may add a sign-in callback to an app's magic-link allow-list,
|
|
3
|
+
* and what to write (#2982).
|
|
4
|
+
*
|
|
5
|
+
* A combined iOS + web app emails ONE https link — the web app's
|
|
6
|
+
* `/oauth/callback` — and the server matches that target against
|
|
7
|
+
* `emailRedirectUris` fail-closed. So init only points an environment's
|
|
8
|
+
* `webUrl` at a dev origin whose callback the app actually allows; otherwise it
|
|
9
|
+
* would flip a working code-only email into a request that 400s.
|
|
10
|
+
*
|
|
11
|
+
* A brand-new app is seeded with `http://localhost:5173/oauth/callback` at
|
|
12
|
+
* creation, and the dev-port step merges the chosen port's callback — but an
|
|
13
|
+
* app adopted with `--use-existing-app-id` on the default port has been through
|
|
14
|
+
* neither, and its allow-list is whatever it already was.
|
|
15
|
+
*
|
|
16
|
+
* The one thing this must never do is NARROW that list. An app with no
|
|
17
|
+
* `emailRedirectUris` attribute still behaves by the pre-#2891 app-wide
|
|
18
|
+
* `redirectUris`, and writing a fresh single-entry list would silently replace
|
|
19
|
+
* that fallback with our callback — breaking magic-link sign-in for whichever
|
|
20
|
+
* client was relying on it. An explicitly empty list is a deliberate "reject
|
|
21
|
+
* everything" for the same reason. Both are left alone, and init falls back to
|
|
22
|
+
* printing the manual step.
|
|
23
|
+
*/
|
|
24
|
+
export type EmailRedirectUriMerge = {
|
|
25
|
+
action: "already-listed";
|
|
26
|
+
} | {
|
|
27
|
+
action: "merge";
|
|
28
|
+
uris: string[];
|
|
29
|
+
} | {
|
|
30
|
+
action: "leave-alone";
|
|
31
|
+
reason: string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Decide what to do with `existing` (the app's `emailRedirectUris` as the
|
|
35
|
+
* settings API reports it) to make `callbackUri` an allowed target.
|
|
36
|
+
*/
|
|
37
|
+
export declare function planEmailRedirectUriMerge(existing: unknown, callbackUri: string): EmailRedirectUriMerge;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether init may add a sign-in callback to an app's magic-link allow-list,
|
|
3
|
+
* and what to write (#2982).
|
|
4
|
+
*
|
|
5
|
+
* A combined iOS + web app emails ONE https link — the web app's
|
|
6
|
+
* `/oauth/callback` — and the server matches that target against
|
|
7
|
+
* `emailRedirectUris` fail-closed. So init only points an environment's
|
|
8
|
+
* `webUrl` at a dev origin whose callback the app actually allows; otherwise it
|
|
9
|
+
* would flip a working code-only email into a request that 400s.
|
|
10
|
+
*
|
|
11
|
+
* A brand-new app is seeded with `http://localhost:5173/oauth/callback` at
|
|
12
|
+
* creation, and the dev-port step merges the chosen port's callback — but an
|
|
13
|
+
* app adopted with `--use-existing-app-id` on the default port has been through
|
|
14
|
+
* neither, and its allow-list is whatever it already was.
|
|
15
|
+
*
|
|
16
|
+
* The one thing this must never do is NARROW that list. An app with no
|
|
17
|
+
* `emailRedirectUris` attribute still behaves by the pre-#2891 app-wide
|
|
18
|
+
* `redirectUris`, and writing a fresh single-entry list would silently replace
|
|
19
|
+
* that fallback with our callback — breaking magic-link sign-in for whichever
|
|
20
|
+
* client was relying on it. An explicitly empty list is a deliberate "reject
|
|
21
|
+
* everything" for the same reason. Both are left alone, and init falls back to
|
|
22
|
+
* printing the manual step.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Decide what to do with `existing` (the app's `emailRedirectUris` as the
|
|
26
|
+
* settings API reports it) to make `callbackUri` an allowed target.
|
|
27
|
+
*/
|
|
28
|
+
export function planEmailRedirectUriMerge(existing, callbackUri) {
|
|
29
|
+
if (!Array.isArray(existing)) {
|
|
30
|
+
return {
|
|
31
|
+
action: "leave-alone",
|
|
32
|
+
reason: "this app has no emailRedirectUris list of its own, and writing one would replace the allow-list it behaves by today",
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const uris = existing.filter((value) => typeof value === "string");
|
|
36
|
+
if (uris.length === 0) {
|
|
37
|
+
return {
|
|
38
|
+
action: "leave-alone",
|
|
39
|
+
reason: "this app's emailRedirectUris list is empty, which is a deliberate 'reject every link target'",
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
if (uris.includes(callbackUri))
|
|
43
|
+
return { action: "already-listed" };
|
|
44
|
+
return { action: "merge", uris: [...uris, callbackUri] };
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=init-email-redirect-uris.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-email-redirect-uris.js","sourceRoot":"","sources":["../../../src/lib/init-email-redirect-uris.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAOH;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CACvC,QAAiB,EACjB,WAAmB;IAEnB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO;YACL,MAAM,EAAE,aAAa;YACrB,MAAM,EACJ,qHAAqH;SACxH,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC;IACpF,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO;YACL,MAAM,EAAE,aAAa;YACrB,MAAM,EACJ,8FAA8F;SACjG,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;IACpE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,WAAW,CAAC,EAAE,CAAC;AAC3D,CAAC"}
|
|
@@ -29,6 +29,20 @@ export interface StampResult {
|
|
|
29
29
|
* serializer would drop them.
|
|
30
30
|
*/
|
|
31
31
|
export declare function stampCallbackScheme(clientDir: string, scheme: string): StampResult;
|
|
32
|
+
/**
|
|
33
|
+
* How to point an environment at the app's web origin — in the shape that
|
|
34
|
+
* actually works (#2982).
|
|
35
|
+
*
|
|
36
|
+
* `primitive env add` CREATES an environment: it requires `--api-url` and
|
|
37
|
+
* refuses a name the config already has. Every environment anyone reads this
|
|
38
|
+
* about already exists (init wrote `dev`; `prod` was added when the app was
|
|
39
|
+
* deployed), so the instruction for those has to be the file, which is also
|
|
40
|
+
* what the docs describe as the way to edit one. The flag is worth naming only
|
|
41
|
+
* where a new environment is being created.
|
|
42
|
+
*
|
|
43
|
+
* `origin` is the placeholder or real origin to show.
|
|
44
|
+
*/
|
|
45
|
+
export declare function setWebUrlInstruction(origin: string, indent?: string): string[];
|
|
32
46
|
/**
|
|
33
47
|
* What init prints about email sign-in on the iOS path: it already works, and
|
|
34
48
|
* this is the one opt-in that adds the link.
|
|
@@ -46,5 +60,31 @@ export declare function stampCallbackScheme(clientDir: string, scheme: string):
|
|
|
46
60
|
export declare function linkOptInGuidance(scheme: string, options?: {
|
|
47
61
|
registered?: boolean;
|
|
48
62
|
}): string[];
|
|
63
|
+
/**
|
|
64
|
+
* What init prints for an app with BOTH clients: the emailed sign-in link is
|
|
65
|
+
* already the web app's https callback, and this is what it takes to make that
|
|
66
|
+
* link open the iOS app in production (#2982).
|
|
67
|
+
*
|
|
68
|
+
* Everything here is a post-deploy step by necessity — the production web
|
|
69
|
+
* domain does not exist at init time, and the deploy script never learns the
|
|
70
|
+
* URL it deployed to. The order is load-bearing: the `applinks:` entitlement
|
|
71
|
+
* is the ONLY thing that makes Apple fetch the association document, and
|
|
72
|
+
* Apple's CDN caches what it gets, so it goes last — after the deployed
|
|
73
|
+
* document has been verified.
|
|
74
|
+
*
|
|
75
|
+
* `webOrigin` is the dev origin the run seeded — set only when the run also
|
|
76
|
+
* confirmed that origin's `/oauth/callback` is on the app's allow-list, since
|
|
77
|
+
* that is what makes the seeded link work.
|
|
78
|
+
*
|
|
79
|
+
* `unverifiedDevCallback` is the opposite case: a combined app whose allow-list
|
|
80
|
+
* this run could not vouch for (an adopted app, or no credentials to ask with).
|
|
81
|
+
* Nothing was seeded — the app keeps its working code-only email — and the two
|
|
82
|
+
* steps that turn the link on are printed instead. Neither is set for an
|
|
83
|
+
* adopting run, which does not own the project config at all.
|
|
84
|
+
*/
|
|
85
|
+
export declare function universalLinkGuidance(options?: {
|
|
86
|
+
webOrigin?: string;
|
|
87
|
+
unverifiedDevCallback?: string;
|
|
88
|
+
}): string[];
|
|
49
89
|
/** What init says when the template predates the `PrimitiveAuth` URL type. */
|
|
50
90
|
export declare function missingUrlTypeGuidance(scheme: string): string[];
|
|
@@ -109,6 +109,26 @@ export function stampCallbackScheme(clientDir, scheme) {
|
|
|
109
109
|
writeFileSync(plistPath, text.slice(0, dictStart) + rewritten + text.slice(dictEnd));
|
|
110
110
|
return { outcome: "stamped" };
|
|
111
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* How to point an environment at the app's web origin — in the shape that
|
|
114
|
+
* actually works (#2982).
|
|
115
|
+
*
|
|
116
|
+
* `primitive env add` CREATES an environment: it requires `--api-url` and
|
|
117
|
+
* refuses a name the config already has. Every environment anyone reads this
|
|
118
|
+
* about already exists (init wrote `dev`; `prod` was added when the app was
|
|
119
|
+
* deployed), so the instruction for those has to be the file, which is also
|
|
120
|
+
* what the docs describe as the way to edit one. The flag is worth naming only
|
|
121
|
+
* where a new environment is being created.
|
|
122
|
+
*
|
|
123
|
+
* `origin` is the placeholder or real origin to show.
|
|
124
|
+
*/
|
|
125
|
+
export function setWebUrlInstruction(origin, indent = " ") {
|
|
126
|
+
return [
|
|
127
|
+
`${indent}add "webUrl": "${origin}" to that environment in .primitive/config.json`,
|
|
128
|
+
`${indent}(\`primitive env add <name> --api-url … --web-url <origin>\` does this only for an`,
|
|
129
|
+
`${indent}environment it CREATES — it cannot edit one that already exists).`,
|
|
130
|
+
];
|
|
131
|
+
}
|
|
112
132
|
/**
|
|
113
133
|
* What init prints about email sign-in on the iOS path: it already works, and
|
|
114
134
|
* this is the one opt-in that adds the link.
|
|
@@ -128,7 +148,11 @@ export function linkOptInGuidance(scheme, options = {}) {
|
|
|
128
148
|
const redirectUri = iosMagicLinkRedirectUri(scheme);
|
|
129
149
|
return [
|
|
130
150
|
"Email sign-in works now: the email carries a 6-digit code and needs no app settings.",
|
|
131
|
-
|
|
151
|
+
"When this app gets a web client, prefer the https link: set the environment's `webUrl` —",
|
|
152
|
+
...setWebUrlInstruction("https://<your-web-domain>"),
|
|
153
|
+
" The email then carries that origin's /oauth/callback instead — one link that opens this",
|
|
154
|
+
" app where it is installed and signs in through the browser anywhere else.",
|
|
155
|
+
`Until then, to ALSO send a sign-in link that opens this app, add "${redirectUri}" to the existing`,
|
|
132
156
|
" [auth].emailRedirectUris array in config/app.toml (merge it in — run",
|
|
133
157
|
" `primitive config pull --only app` first if that file is not there yet), then run",
|
|
134
158
|
" `primitive config push --only app` and set `authManager.sendsEmailSignInLink = true`.",
|
|
@@ -140,6 +164,47 @@ export function linkOptInGuidance(scheme, options = {}) {
|
|
|
140
164
|
" authentication.md docs page — 'Make the emailed sign-in link open your app'.",
|
|
141
165
|
];
|
|
142
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* What init prints for an app with BOTH clients: the emailed sign-in link is
|
|
169
|
+
* already the web app's https callback, and this is what it takes to make that
|
|
170
|
+
* link open the iOS app in production (#2982).
|
|
171
|
+
*
|
|
172
|
+
* Everything here is a post-deploy step by necessity — the production web
|
|
173
|
+
* domain does not exist at init time, and the deploy script never learns the
|
|
174
|
+
* URL it deployed to. The order is load-bearing: the `applinks:` entitlement
|
|
175
|
+
* is the ONLY thing that makes Apple fetch the association document, and
|
|
176
|
+
* Apple's CDN caches what it gets, so it goes last — after the deployed
|
|
177
|
+
* document has been verified.
|
|
178
|
+
*
|
|
179
|
+
* `webOrigin` is the dev origin the run seeded — set only when the run also
|
|
180
|
+
* confirmed that origin's `/oauth/callback` is on the app's allow-list, since
|
|
181
|
+
* that is what makes the seeded link work.
|
|
182
|
+
*
|
|
183
|
+
* `unverifiedDevCallback` is the opposite case: a combined app whose allow-list
|
|
184
|
+
* this run could not vouch for (an adopted app, or no credentials to ask with).
|
|
185
|
+
* Nothing was seeded — the app keeps its working code-only email — and the two
|
|
186
|
+
* steps that turn the link on are printed instead. Neither is set for an
|
|
187
|
+
* adopting run, which does not own the project config at all.
|
|
188
|
+
*/
|
|
189
|
+
export function universalLinkGuidance(options = {}) {
|
|
190
|
+
const lines = [
|
|
191
|
+
"This app has both an iOS and a web client, so its sign-in email carries ONE https link:",
|
|
192
|
+
" the web app's /oauth/callback. Tapped where the iOS app is installed it opens the app;",
|
|
193
|
+
" anywhere else it is an ordinary web sign-in. The 6-digit code still works everywhere.",
|
|
194
|
+
];
|
|
195
|
+
if (options.webOrigin) {
|
|
196
|
+
lines.push(`In dev that link is ${options.webOrigin}/oauth/callback — seeded as the environment's`, " `webUrl`, and allow-listed on the app. Nothing to do.");
|
|
197
|
+
}
|
|
198
|
+
else if (options.unverifiedDevCallback) {
|
|
199
|
+
const origin = options.unverifiedDevCallback.replace(/\/oauth\/callback$/, "");
|
|
200
|
+
lines.push("The link is NOT on yet in dev: this app already existed, and its sign-in link allow-list", ` does not (or could not be checked to) carry ${options.unverifiedDevCallback}. Nothing was`, " changed — the email stays code-only, which works. To turn the link on:", ` 1. Merge "${options.unverifiedDevCallback}" into the existing [auth].emailRedirectUris`, " array in config/app.toml (run `primitive config pull --only app` first if that file is", " not there yet), then `primitive config push --only app`.", ` 2. Then ${setWebUrlInstruction(origin, "")[0]}`, " — the same edit the production steps below describe.");
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
lines.push("Set `webUrl` on this app's environment to turn it on (this run did not write the", " project config):", ...setWebUrlInstruction("https://<your-web-domain>"), " Allow-list that origin's /oauth/callback in [auth].emailRedirectUris too.");
|
|
204
|
+
}
|
|
205
|
+
lines.push("For production, once the web app is deployed:", " 1. Set that environment's `webUrl` to the deployed origin —", ...setWebUrlInstruction("https://<your-web-domain>", " "), " 2. Merge \"https://<your-web-domain>/oauth/callback\" into the existing", " [auth].emailRedirectUris array in config/app.toml (run `primitive config pull --only app`", " first if that file is not there yet), then `primitive config push --only app`.", " 3. In the web client, fill your Apple team and bundle ids into", " public/.well-known/apple-app-site-association.example and rename it (drop .example).", " 4. Deploy, then verify: `curl -i https://<your-web-domain>/.well-known/apple-app-site-association`", " must return 200, application/json and the JSON body — HTML means the SPA fallback answered.", " 5. Only then enable the `applinks:<your-web-domain>` entitlement in the iOS client's", " project.yml (it needs a real DEVELOPMENT_TEAM) and reinstall the app.", " Full checklist: the web client's public/.well-known/README.md, or the authentication", " docs page — 'Make the emailed sign-in link open your app'.");
|
|
206
|
+
return lines;
|
|
207
|
+
}
|
|
143
208
|
/** What init says when the template predates the `PrimitiveAuth` URL type. */
|
|
144
209
|
export function missingUrlTypeGuidance(scheme) {
|
|
145
210
|
return [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init-ios-links.js","sourceRoot":"","sources":["../../../src/lib/init-ios-links.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"init-ios-links.js","sourceRoot":"","sources":["../../../src/lib/init-ios-links.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the identifier the `integrations tests` verbs take (issue #3000).
|
|
3
|
+
*
|
|
4
|
+
* The block-testing endpoints key on the composite `integration#<blockId>` and
|
|
5
|
+
* never check that the block exists, so an identifier that names no
|
|
6
|
+
* integration came back as an empty page rather than a 404: `tests list`
|
|
7
|
+
* printed "No test cases found." and `tests run-all` printed
|
|
8
|
+
* `Total Tests: 0 / Failed: 0` and exited 0. That is success-shaped in CI and
|
|
9
|
+
* indistinguishable from an integration that genuinely has no cases, so a
|
|
10
|
+
* typo, an integration KEY, or an ID from another app all read as "nothing to
|
|
11
|
+
* run".
|
|
12
|
+
*
|
|
13
|
+
* Resolving here — against the app's own integration list — is what makes
|
|
14
|
+
* `Total Tests: 0` mean "this integration exists and has no cases". The list
|
|
15
|
+
* is the one call that can answer both halves: it maps a key to its ID (keys
|
|
16
|
+
* are stored lowercased, so the match is case-insensitive) and it proves the
|
|
17
|
+
* identifier belongs to THIS app. Archived integrations are included, because
|
|
18
|
+
* their cases stay inspectable.
|
|
19
|
+
*/
|
|
20
|
+
export interface ResolvedIntegration {
|
|
21
|
+
integrationId: string;
|
|
22
|
+
/** The integration's key, when the summary carries one. */
|
|
23
|
+
integrationKey?: string;
|
|
24
|
+
}
|
|
25
|
+
/** The one method this resolver needs from `ApiClient`. */
|
|
26
|
+
export interface IntegrationLister {
|
|
27
|
+
listIntegrations(appId: string, params?: {
|
|
28
|
+
status?: string;
|
|
29
|
+
cursor?: string;
|
|
30
|
+
limit?: number;
|
|
31
|
+
}): Promise<{
|
|
32
|
+
items: any[];
|
|
33
|
+
nextCursor?: string | null;
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Map an integration ID or key to its integration ID.
|
|
38
|
+
*
|
|
39
|
+
* Throws — naming the identifier — when nothing in the app matches, so the
|
|
40
|
+
* caller's existing catch prints the message and exits non-zero.
|
|
41
|
+
*/
|
|
42
|
+
export declare function resolveIntegrationSelector(client: IntegrationLister, appId: string, selector: string): Promise<ResolvedIntegration>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the identifier the `integrations tests` verbs take (issue #3000).
|
|
3
|
+
*
|
|
4
|
+
* The block-testing endpoints key on the composite `integration#<blockId>` and
|
|
5
|
+
* never check that the block exists, so an identifier that names no
|
|
6
|
+
* integration came back as an empty page rather than a 404: `tests list`
|
|
7
|
+
* printed "No test cases found." and `tests run-all` printed
|
|
8
|
+
* `Total Tests: 0 / Failed: 0` and exited 0. That is success-shaped in CI and
|
|
9
|
+
* indistinguishable from an integration that genuinely has no cases, so a
|
|
10
|
+
* typo, an integration KEY, or an ID from another app all read as "nothing to
|
|
11
|
+
* run".
|
|
12
|
+
*
|
|
13
|
+
* Resolving here — against the app's own integration list — is what makes
|
|
14
|
+
* `Total Tests: 0` mean "this integration exists and has no cases". The list
|
|
15
|
+
* is the one call that can answer both halves: it maps a key to its ID (keys
|
|
16
|
+
* are stored lowercased, so the match is case-insensitive) and it proves the
|
|
17
|
+
* identifier belongs to THIS app. Archived integrations are included, because
|
|
18
|
+
* their cases stay inspectable.
|
|
19
|
+
*/
|
|
20
|
+
import { paginateAll } from "./paginate.js";
|
|
21
|
+
/**
|
|
22
|
+
* Map an integration ID or key to its integration ID.
|
|
23
|
+
*
|
|
24
|
+
* Throws — naming the identifier — when nothing in the app matches, so the
|
|
25
|
+
* caller's existing catch prints the message and exits non-zero.
|
|
26
|
+
*/
|
|
27
|
+
export async function resolveIntegrationSelector(client, appId, selector) {
|
|
28
|
+
const identifier = (selector ?? "").trim();
|
|
29
|
+
if (!identifier) {
|
|
30
|
+
throw new Error("An integration ID or key is required.");
|
|
31
|
+
}
|
|
32
|
+
const items = await paginateAll((cursor) => client.listIntegrations(appId, cursor ? { cursor } : {}));
|
|
33
|
+
const lowered = identifier.toLowerCase();
|
|
34
|
+
const match = items.find((item) => item?.integrationId === identifier) ??
|
|
35
|
+
items.find((item) => typeof item?.integrationKey === "string" &&
|
|
36
|
+
item.integrationKey.toLowerCase() === lowered);
|
|
37
|
+
if (!match) {
|
|
38
|
+
throw new Error(`No integration '${identifier}' in app ${appId}. ` +
|
|
39
|
+
`Pass an integration key or ID from 'primitive integrations list'.`);
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
integrationId: match.integrationId ?? identifier,
|
|
43
|
+
...(match.integrationKey ? { integrationKey: match.integrationKey } : {}),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=integration-selector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration-selector.js","sourceRoot":"","sources":["../../../src/lib/integration-selector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAgB5C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,MAAyB,EACzB,KAAa,EACb,QAAgB;IAEhB,MAAM,UAAU,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3C,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,WAAW,CAAM,CAAC,MAAM,EAAE,EAAE,CAC9C,MAAM,CAAC,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CACzD,CAAC;IAEF,MAAM,OAAO,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;IACzC,MAAM,KAAK,GACT,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,UAAU,CAAC;QACxD,KAAK,CAAC,IAAI,CACR,CAAC,IAAI,EAAE,EAAE,CACP,OAAO,IAAI,EAAE,cAAc,KAAK,QAAQ;YACxC,IAAI,CAAC,cAAc,CAAC,WAAW,EAAE,KAAK,OAAO,CAChD,CAAC;IAEJ,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,mBAAmB,UAAU,YAAY,KAAK,IAAI;YAChD,mEAAmE,CACtE,CAAC;IACJ,CAAC;IAED,OAAO;QACL,aAAa,EAAE,KAAK,CAAC,aAAa,IAAI,UAAU;QAChD,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1E,CAAC;AACJ,CAAC"}
|