typeferry 0.10.0 → 0.12.0
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/application/build.d.ts +2 -2
- package/dist/application/build.js +8 -2
- package/dist/application/build.js.map +1 -1
- package/dist/application/cli-arguments.d.ts +39 -2
- package/dist/application/cli-arguments.js +59 -1
- package/dist/application/cli-arguments.js.map +1 -1
- package/dist/application/config.d.ts +57 -1
- package/dist/application/config.js +36 -0
- package/dist/application/config.js.map +1 -1
- package/dist/application/native-command.d.ts +35 -0
- package/dist/application/native-command.js +148 -0
- package/dist/application/native-command.js.map +1 -0
- package/dist/application/native-devices.d.ts +31 -0
- package/dist/application/native-devices.js +94 -0
- package/dist/application/native-devices.js.map +1 -0
- package/dist/application/native-doctor.d.ts +17 -0
- package/dist/application/native-doctor.js +79 -0
- package/dist/application/native-doctor.js.map +1 -0
- package/dist/application/native-project.d.ts +16 -0
- package/dist/application/native-project.js +82 -0
- package/dist/application/native-project.js.map +1 -0
- package/dist/application/native-simulator-settings.d.ts +24 -0
- package/dist/application/native-simulator-settings.js +55 -0
- package/dist/application/native-simulator-settings.js.map +1 -0
- package/dist/application/native-simulator.d.ts +19 -0
- package/dist/application/native-simulator.js +101 -0
- package/dist/application/native-simulator.js.map +1 -0
- package/dist/application/native.d.ts +2 -0
- package/dist/application/native.js +86 -0
- package/dist/application/native.js.map +1 -0
- package/dist/application/runtime.d.ts +13 -0
- package/dist/application/runtime.js +15 -0
- package/dist/application/runtime.js.map +1 -0
- package/dist/application/vite-config.d.ts +2 -2
- package/dist/application/vite-config.js +16 -2
- package/dist/application/vite-config.js.map +1 -1
- package/dist/auth/client/index.d.ts +4 -0
- package/dist/auth/client/index.js +2 -0
- package/dist/auth/client/index.js.map +1 -1
- package/dist/auth/client/native-http.d.ts +24 -0
- package/dist/auth/client/native-http.js +19 -0
- package/dist/auth/client/native-http.js.map +1 -0
- package/dist/auth/client/native-session.d.ts +34 -0
- package/dist/auth/client/native-session.js +65 -0
- package/dist/auth/client/native-session.js.map +1 -0
- package/dist/auth/index.d.ts +6 -0
- package/dist/auth/index.js +3 -0
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/server/native-handoff.d.ts +69 -0
- package/dist/auth/server/native-handoff.js +65 -0
- package/dist/auth/server/native-handoff.js.map +1 -0
- package/dist/cli/index.js +5 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/run.js +18 -1
- package/dist/cli/run.js.map +1 -1
- package/dist/client/backend-origin.d.ts +17 -0
- package/dist/client/backend-origin.js +25 -0
- package/dist/client/backend-origin.js.map +1 -0
- package/dist/client/client-http.js +8 -3
- package/dist/client/client-http.js.map +1 -1
- package/dist/client/client-socket.js +6 -1
- package/dist/client/client-socket.js.map +1 -1
- package/dist/client/client.d.ts +9 -0
- package/dist/client/client.js.map +1 -1
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.js +1 -0
- package/dist/client/index.js.map +1 -1
- package/dist/ejson/clone.js +7 -1
- package/dist/ejson/clone.js.map +1 -1
- package/dist/native/index.d.ts +76 -0
- package/dist/native/index.js +5 -0
- package/dist/native/index.js.map +1 -0
- package/dist/native/share-file.d.ts +18 -0
- package/dist/native/share-file.js +41 -0
- package/dist/native/share-file.js.map +1 -0
- package/dist/native/templates/bridge-view-controller.d.ts +4 -0
- package/dist/native/templates/bridge-view-controller.js +86 -0
- package/dist/native/templates/bridge-view-controller.js.map +1 -0
- package/dist/native/templates/file-staging.d.ts +4 -0
- package/dist/native/templates/file-staging.js +77 -0
- package/dist/native/templates/file-staging.js.map +1 -0
- package/dist/native/templates/http-session.d.ts +4 -0
- package/dist/native/templates/http-session.js +117 -0
- package/dist/native/templates/http-session.js.map +1 -0
- package/dist/native/templates/index.d.ts +4 -0
- package/dist/native/templates/index.js +20 -0
- package/dist/native/templates/index.js.map +1 -0
- package/dist/native/templates/keychain.d.ts +4 -0
- package/dist/native/templates/keychain.js +48 -0
- package/dist/native/templates/keychain.js.map +1 -0
- package/dist/native/templates/media-permission-policy.d.ts +4 -0
- package/dist/native/templates/media-permission-policy.js +24 -0
- package/dist/native/templates/media-permission-policy.js.map +1 -0
- package/dist/native/templates/plugin.d.ts +4 -0
- package/dist/native/templates/plugin.js +314 -0
- package/dist/native/templates/plugin.js.map +1 -0
- package/dist/native/templates/wake-locks.d.ts +4 -0
- package/dist/native/templates/wake-locks.js +47 -0
- package/dist/native/templates/wake-locks.js.map +1 -0
- package/dist/native/wake-lock.d.ts +9 -0
- package/dist/native/wake-lock.js +17 -0
- package/dist/native/wake-lock.js.map +1 -0
- package/package.json +18 -2
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { promisify } from 'node:util';
|
|
6
|
+
import { fileExists, registerNativeScene, registerNativeSource, writeGeneratedFile } from './native-project.js';
|
|
7
|
+
const execute = promisify(execFile);
|
|
8
|
+
export async function runNative(config, action) {
|
|
9
|
+
const ios = config.client.targets.ios;
|
|
10
|
+
const identity = config.application;
|
|
11
|
+
if (!ios || !identity)
|
|
12
|
+
throw new Error('Configure application identity and client.targets.ios first');
|
|
13
|
+
const require = createRequire(path.join(config.root, 'package.json'));
|
|
14
|
+
let cli;
|
|
15
|
+
try {
|
|
16
|
+
cli = require.resolve('@capacitor/cli/bin/capacitor');
|
|
17
|
+
require.resolve('@capacitor/ios/package.json');
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
throw new Error('Install @capacitor/core, @capacitor/ios and @capacitor/cli in the application before using native commands');
|
|
21
|
+
}
|
|
22
|
+
for (const extension of ['ts', 'js']) {
|
|
23
|
+
if (await fileExists(path.join(config.root, `capacitor.config.${extension}`)))
|
|
24
|
+
throw new Error('Existing Capacitor configuration must be reconciled before TypeFerry can own native configuration');
|
|
25
|
+
}
|
|
26
|
+
await writeGeneratedFile(config.root, 'capacitor.config.json', `${JSON.stringify({
|
|
27
|
+
appId: identity.id,
|
|
28
|
+
appName: identity.name,
|
|
29
|
+
loggingBehavior: 'none',
|
|
30
|
+
webDir: 'dist/ios-web',
|
|
31
|
+
ios: { path: 'ios' },
|
|
32
|
+
plugins: { TypeFerryNative: { backendOrigin: ios.backend.origin, callbackScheme: identity.id } },
|
|
33
|
+
}, null, 2)}\n`);
|
|
34
|
+
const { stdout, stderr } = await execute(process.execPath, [cli, action, 'ios'], { cwd: config.root, maxBuffer: 8 * 1024 * 1024 });
|
|
35
|
+
if (stdout)
|
|
36
|
+
process.stdout.write(stdout);
|
|
37
|
+
if (stderr)
|
|
38
|
+
process.stderr.write(stderr);
|
|
39
|
+
if (action === 'open')
|
|
40
|
+
return;
|
|
41
|
+
await configureNativeProject(config);
|
|
42
|
+
}
|
|
43
|
+
async function configureNativeProject(config) {
|
|
44
|
+
const { IOS_NATIVE_TEMPLATES } = await import('../native/templates/index.js');
|
|
45
|
+
await writeGeneratedFile(config.root, 'ios/App/App/TypeFerryNative.swift', Object.values(IOS_NATIVE_TEMPLATES).join('\n'));
|
|
46
|
+
const projectPath = path.join(config.root, 'ios/App/App.xcodeproj/project.pbxproj');
|
|
47
|
+
const project = await readFile(projectPath, 'utf8');
|
|
48
|
+
const registered = registerNativeSource(project);
|
|
49
|
+
if (registered !== project)
|
|
50
|
+
await writeFile(projectPath, registered);
|
|
51
|
+
const scenePath = path.join(config.root, 'ios/App/App/SceneDelegate.swift');
|
|
52
|
+
if (await fileExists(scenePath)) {
|
|
53
|
+
const scene = await readFile(scenePath, 'utf8');
|
|
54
|
+
const updated = registerNativeScene(scene);
|
|
55
|
+
if (updated !== scene)
|
|
56
|
+
await writeFile(scenePath, updated);
|
|
57
|
+
}
|
|
58
|
+
const storyboardPath = path.join(config.root, 'ios/App/App/Base.lproj/Main.storyboard');
|
|
59
|
+
const storyboard = await readFile(storyboardPath, 'utf8');
|
|
60
|
+
if (storyboard.includes('customClass="CAPBridgeViewController"')) {
|
|
61
|
+
await writeFile(storyboardPath, storyboard.replace('customClass="CAPBridgeViewController" customModule="Capacitor"', 'customClass="TypeFerryBridgeViewController" customModule="App" customModuleProvider="target"'));
|
|
62
|
+
}
|
|
63
|
+
else if (!storyboard.includes('customClass="TypeFerryBridgeViewController"')) {
|
|
64
|
+
throw new Error('Custom bridge controller detected; integrate TypeFerry native registration explicitly');
|
|
65
|
+
}
|
|
66
|
+
const plist = path.join(config.root, 'ios/App/App/Info.plist');
|
|
67
|
+
const permissions = config.client.targets.ios?.permissions;
|
|
68
|
+
for (const [key, purpose] of [
|
|
69
|
+
['NSCameraUsageDescription', permissions?.camera?.purpose],
|
|
70
|
+
['NSMicrophoneUsageDescription', permissions?.microphone?.purpose],
|
|
71
|
+
]) {
|
|
72
|
+
if (purpose)
|
|
73
|
+
await execute('/usr/bin/plutil', ['-replace', key, '-string', purpose, plist]);
|
|
74
|
+
}
|
|
75
|
+
const callbackScheme = config.application?.id;
|
|
76
|
+
if (callbackScheme) {
|
|
77
|
+
const existing = await execute('/usr/bin/plutil', ['-extract', 'CFBundleURLTypes', 'json', '-o', '-', plist]).catch(() => null);
|
|
78
|
+
const value = existing ? JSON.parse(existing.stdout) : [];
|
|
79
|
+
if (!Array.isArray(value))
|
|
80
|
+
throw new Error('Invalid CFBundleURLTypes in app Info.plist');
|
|
81
|
+
const includesScheme = value.some((entry) => typeof entry === 'object' && entry !== null && 'CFBundleURLSchemes' in entry && Array.isArray(entry.CFBundleURLSchemes) && entry.CFBundleURLSchemes.includes(callbackScheme));
|
|
82
|
+
if (!includesScheme)
|
|
83
|
+
await execute('/usr/bin/plutil', ['-replace', 'CFBundleURLTypes', '-json', JSON.stringify([...value, { CFBundleURLName: 'TypeFerry authentication', CFBundleURLSchemes: [callbackScheme] }]), plist]);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=native.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native.js","sourceRoot":"","sources":["../../src/application/native.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public, non-secret build metadata. Browser builds retain same-origin behavior;
|
|
3
|
+
* native builds embed only the explicitly configured backend origin.
|
|
4
|
+
*/
|
|
5
|
+
export interface ApplicationRuntime {
|
|
6
|
+
readonly target: 'web' | 'ios';
|
|
7
|
+
readonly backendOrigin?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function getApplicationRuntime(): ApplicationRuntime;
|
|
10
|
+
/**
|
|
11
|
+
* Resolves backend-owned paths without rewriting external provider URLs.
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveBackendUrl(path: string): string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function getApplicationRuntime() {
|
|
2
|
+
return typeof __TYPEFERRY_RUNTIME__ === 'undefined'
|
|
3
|
+
? { target: 'web' }
|
|
4
|
+
: __TYPEFERRY_RUNTIME__;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Resolves backend-owned paths without rewriting external provider URLs.
|
|
8
|
+
*/
|
|
9
|
+
export function resolveBackendUrl(path) {
|
|
10
|
+
const { backendOrigin } = getApplicationRuntime();
|
|
11
|
+
if (!backendOrigin || !path.startsWith('/') || path.startsWith('//'))
|
|
12
|
+
return path;
|
|
13
|
+
return new URL(path, backendOrigin).href;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/application/runtime.ts"],"names":[],"mappings":"AAWA,MAAM,UAAU,qBAAqB;IACnC,OAAO,OAAO,qBAAqB,KAAK,WAAW;QACjD,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE;QACnB,CAAC,CAAC,qBAAqB,CAAA;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,EAAE,aAAa,EAAE,GAAG,qBAAqB,EAAE,CAAA;IACjD,IAAI,CAAC,aAAa,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IACjF,OAAO,IAAI,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC,IAAI,CAAA;AAC1C,CAAC"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { InlineConfig } from "vite";
|
|
2
|
-
import type { ResolvedApplicationConfig } from "./config.js";
|
|
3
|
-
export declare function createViteConfig(config: ResolvedApplicationConfig, command: "develop" | "build"): InlineConfig;
|
|
2
|
+
import type { ApplicationTarget, ResolvedApplicationConfig } from "./config.js";
|
|
3
|
+
export declare function createViteConfig(config: ResolvedApplicationConfig, command: "develop" | "build", target?: ApplicationTarget): InlineConfig;
|
|
@@ -2,7 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
import tailwindcss from "@tailwindcss/vite";
|
|
3
3
|
import react from "@vitejs/plugin-react";
|
|
4
4
|
import { createTypeFerryDevProxy } from "./proxy.js";
|
|
5
|
-
export function createViteConfig(config, command) {
|
|
5
|
+
export function createViteConfig(config, command, target = "web") {
|
|
6
6
|
const plugins = [react(), tailwindcss()];
|
|
7
7
|
if (command === "develop") {
|
|
8
8
|
plugins.unshift(createTypeFerryDevProxy(config.development.serverPort, config.development.proxyRoutes));
|
|
@@ -39,6 +39,20 @@ export function createViteConfig(config, command) {
|
|
|
39
39
|
},
|
|
40
40
|
},
|
|
41
41
|
};
|
|
42
|
-
|
|
42
|
+
if (target === 'ios') {
|
|
43
|
+
const ios = config.client.targets.ios;
|
|
44
|
+
if (!ios)
|
|
45
|
+
throw new Error('No iOS application target configured');
|
|
46
|
+
viteConfig.build = { ...viteConfig.build, outDir: '../dist/ios-web' };
|
|
47
|
+
viteConfig.define = { __TYPEFERRY_RUNTIME__: JSON.stringify({ target, backendOrigin: ios.backend.origin }) };
|
|
48
|
+
}
|
|
49
|
+
const extended = config.extensions.vite?.(viteConfig, { command, target }) ?? viteConfig;
|
|
50
|
+
if (target === 'ios' && extended.define?.__TYPEFERRY_RUNTIME__ !== viteConfig.define?.__TYPEFERRY_RUNTIME__) {
|
|
51
|
+
throw new Error('iOS public runtime metadata must be preserved by Vite extensions');
|
|
52
|
+
}
|
|
53
|
+
if (target === 'ios' && extended.build?.outDir !== '../dist/ios-web') {
|
|
54
|
+
throw new Error('iOS output must remain isolated in dist/ios-web');
|
|
55
|
+
}
|
|
56
|
+
return extended;
|
|
43
57
|
}
|
|
44
58
|
//# sourceMappingURL=vite-config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite-config.js","sourceRoot":"","sources":["../../src/application/vite-config.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,WAAW,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,MAAM,sBAAsB,CAAC;AAIzC,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAElD,MAAM,UAAU,gBAAgB,CAC9B,MAAiC,EACjC,OAA4B;
|
|
1
|
+
{"version":3,"file":"vite-config.js","sourceRoot":"","sources":["../../src/application/vite-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,6 @@
|
|
|
1
1
|
export { broadcastTokenRefresh, setupCrossTabSync } from './cross-tab-sync.js';
|
|
2
2
|
export { refreshAccessToken, setupTokenRefreshOnExpiry } from './token-refresh.js';
|
|
3
|
+
export { authenticateNativeSession } from './native-session.js';
|
|
4
|
+
export type { NativeAccessSession, NativeSessionOptions } from './native-session.js';
|
|
5
|
+
export { createNativeHttpFetch } from './native-http.js';
|
|
6
|
+
export type { NativeHttpBridge } from './native-http.js';
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { broadcastTokenRefresh, setupCrossTabSync } from './cross-tab-sync.js';
|
|
2
2
|
export { refreshAccessToken, setupTokenRefreshOnExpiry } from './token-refresh.js';
|
|
3
|
+
export { authenticateNativeSession } from './native-session.js';
|
|
4
|
+
export { createNativeHttpFetch } from './native-http.js';
|
|
3
5
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/auth/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAC3E,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/auth/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAC3E,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAA;AAC/E,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAA;AAE5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { HttpFetch } from '../../client/backend-origin.js';
|
|
2
|
+
/**
|
|
3
|
+
* Text-only native transport. Its implementation must pin the backend origin,
|
|
4
|
+
* persist cookies privately, reject off-origin redirects and hide Set-Cookie.
|
|
5
|
+
*/
|
|
6
|
+
export interface NativeHttpBridge {
|
|
7
|
+
request(options: {
|
|
8
|
+
url: string;
|
|
9
|
+
method: string;
|
|
10
|
+
headers: Record<string, string>;
|
|
11
|
+
body?: string;
|
|
12
|
+
}): Promise<{
|
|
13
|
+
status: number;
|
|
14
|
+
statusText: string;
|
|
15
|
+
headers: Record<string, string>;
|
|
16
|
+
body: string;
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Adapts native private-cookie HTTP to ClientOptions.httpFetch. This boundary is
|
|
21
|
+
* for RPC and auth JSON, not binary uploads/downloads. Cancellation is checked
|
|
22
|
+
* before and after the native operation; it does not undo server-side effects.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createNativeHttpFetch(bridge: NativeHttpBridge): HttpFetch;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapts native private-cookie HTTP to ClientOptions.httpFetch. This boundary is
|
|
3
|
+
* for RPC and auth JSON, not binary uploads/downloads. Cancellation is checked
|
|
4
|
+
* before and after the native operation; it does not undo server-side effects.
|
|
5
|
+
*/
|
|
6
|
+
export function createNativeHttpFetch(bridge) {
|
|
7
|
+
return async (url, options = {}) => {
|
|
8
|
+
options.signal?.throwIfAborted();
|
|
9
|
+
if (options.body != null && typeof options.body !== 'string') {
|
|
10
|
+
throw new Error('Native HTTP adapter supports text request bodies only');
|
|
11
|
+
}
|
|
12
|
+
const headers = Object.fromEntries(new Headers(options.headers).entries());
|
|
13
|
+
const result = await bridge.request({ url, method: options.method ?? 'GET', headers, ...(typeof options.body === 'string' ? { body: options.body } : {}) });
|
|
14
|
+
options.signal?.throwIfAborted();
|
|
15
|
+
const body = [204, 205, 304].includes(result.status) ? null : result.body;
|
|
16
|
+
return new Response(body, { status: result.status, statusText: result.statusText, headers: result.headers });
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=native-http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-http.js","sourceRoot":"","sources":["../../../src/auth/client/native-http.ts"],"names":[],"mappings":"AAeA;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAwB;IAC5D,OAAO,KAAK,EAAE,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,EAAE;QACjC,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,CAAA;QAEhC,IAAI,OAAO,CAAC,IAAI,IAAI,IAAI,IAAI,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7D,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAA;QAC1E,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC,CAAA;QAC1E,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;QAE3J,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,CAAA;QAEhC,MAAM,IAAI,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAA;QAEzE,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAA;IAC9G,CAAC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { HttpFetch } from '../../client/backend-origin.js';
|
|
2
|
+
/**
|
|
3
|
+
* Public access context returned by the application exchange endpoint.
|
|
4
|
+
* The refresh credential stays in the native HTTP cookie store.
|
|
5
|
+
*/
|
|
6
|
+
export interface NativeAccessSession {
|
|
7
|
+
token: string;
|
|
8
|
+
exp: number;
|
|
9
|
+
iat: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* An external system-browser handoff and its application-owned endpoints.
|
|
13
|
+
* httpFetch must use the same private native cookie store as the RPC client.
|
|
14
|
+
*/
|
|
15
|
+
export interface NativeSessionOptions {
|
|
16
|
+
backendOrigin: string;
|
|
17
|
+
authorizationPath: string;
|
|
18
|
+
exchangePath: string;
|
|
19
|
+
redirectUri: string;
|
|
20
|
+
authenticate(options: {
|
|
21
|
+
url: string;
|
|
22
|
+
callbackScheme: string;
|
|
23
|
+
}): Promise<{
|
|
24
|
+
url: string;
|
|
25
|
+
}>;
|
|
26
|
+
httpFetch: HttpFetch;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Authenticates in an external browser with PKCE S256 and a fresh state value.
|
|
30
|
+
* Exchanges the returned code through native HTTP to establish its private
|
|
31
|
+
* refresh cookie. The caller installs the returned access context on its Client.
|
|
32
|
+
* No refresh credential or PKCE verifier is placed in a callback URL.
|
|
33
|
+
*/
|
|
34
|
+
export declare function authenticateNativeSession(options: NativeSessionOptions): Promise<NativeAccessSession>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { resolveBackendOrigins } from '../../client/backend-origin.js';
|
|
2
|
+
function base64Url(bytes) {
|
|
3
|
+
return btoa(String.fromCharCode(...bytes)).replaceAll('+', '-').replaceAll('/', '_').replaceAll('=', '');
|
|
4
|
+
}
|
|
5
|
+
function endpoint(path, origin) {
|
|
6
|
+
const url = new URL(path, origin);
|
|
7
|
+
if (url.origin !== origin || url.username || url.password || url.hash) {
|
|
8
|
+
throw new Error('Native authentication endpoint must use the backend origin');
|
|
9
|
+
}
|
|
10
|
+
return url;
|
|
11
|
+
}
|
|
12
|
+
function readCallback(value, expected, state) {
|
|
13
|
+
const callback = new URL(value);
|
|
14
|
+
const codes = callback.searchParams.getAll('code');
|
|
15
|
+
const states = callback.searchParams.getAll('state');
|
|
16
|
+
if (callback.protocol !== expected.protocol || callback.host !== expected.host || callback.pathname !== expected.pathname || callback.username || callback.password || callback.hash || codes.length !== 1 || states.length !== 1 || states[0] !== state || !/^[A-Za-z0-9_-]{43}$/.test(codes[0]) || callback.searchParams.has('error')) {
|
|
17
|
+
throw new Error('Invalid native authentication callback');
|
|
18
|
+
}
|
|
19
|
+
return codes[0];
|
|
20
|
+
}
|
|
21
|
+
function isAccessSession(value) {
|
|
22
|
+
if (typeof value !== 'object' || value === null)
|
|
23
|
+
return false;
|
|
24
|
+
return 'token' in value && typeof value.token === 'string' && value.token.length > 0
|
|
25
|
+
&& 'exp' in value && typeof value.exp === 'number' && Number.isFinite(value.exp)
|
|
26
|
+
&& 'iat' in value && typeof value.iat === 'number' && Number.isFinite(value.iat)
|
|
27
|
+
&& value.exp > value.iat;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Authenticates in an external browser with PKCE S256 and a fresh state value.
|
|
31
|
+
* Exchanges the returned code through native HTTP to establish its private
|
|
32
|
+
* refresh cookie. The caller installs the returned access context on its Client.
|
|
33
|
+
* No refresh credential or PKCE verifier is placed in a callback URL.
|
|
34
|
+
*/
|
|
35
|
+
export async function authenticateNativeSession(options) {
|
|
36
|
+
const origin = resolveBackendOrigins({ httpOrigin: options.backendOrigin }).httpOrigin;
|
|
37
|
+
const authorization = endpoint(options.authorizationPath, origin);
|
|
38
|
+
const exchange = endpoint(options.exchangePath, origin);
|
|
39
|
+
const redirect = new URL(options.redirectUri);
|
|
40
|
+
if (!redirect.protocol.includes('.') || redirect.username || redirect.password || redirect.search || redirect.hash) {
|
|
41
|
+
throw new Error('Native redirect URI must use a reverse-domain app scheme without credentials, query or fragment');
|
|
42
|
+
}
|
|
43
|
+
const verifier = base64Url(crypto.getRandomValues(new Uint8Array(32)));
|
|
44
|
+
const state = base64Url(crypto.getRandomValues(new Uint8Array(32)));
|
|
45
|
+
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier));
|
|
46
|
+
authorization.searchParams.set('redirect_uri', options.redirectUri);
|
|
47
|
+
authorization.searchParams.set('code_challenge', base64Url(new Uint8Array(digest)));
|
|
48
|
+
authorization.searchParams.set('code_challenge_method', 'S256');
|
|
49
|
+
authorization.searchParams.set('state', state);
|
|
50
|
+
const callback = await options.authenticate({ url: authorization.href, callbackScheme: redirect.protocol.slice(0, -1) });
|
|
51
|
+
const code = readCallback(callback.url, redirect, state);
|
|
52
|
+
const response = await options.httpFetch(exchange.href, {
|
|
53
|
+
method: 'POST',
|
|
54
|
+
credentials: 'include',
|
|
55
|
+
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
|
|
56
|
+
body: JSON.stringify({ code, codeVerifier: verifier, redirectUri: options.redirectUri }),
|
|
57
|
+
});
|
|
58
|
+
if (!response.ok)
|
|
59
|
+
throw new Error(`Native authentication exchange failed (${response.status})`);
|
|
60
|
+
const result = await response.json();
|
|
61
|
+
if (!isAccessSession(result))
|
|
62
|
+
throw new Error('Invalid native access session');
|
|
63
|
+
return { token: result.token, exp: result.exp, iat: result.iat };
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=native-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-session.js","sourceRoot":"","sources":["../../../src/auth/client/native-session.ts"],"names":[],"mappings":"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"}
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -5,3 +5,9 @@ export { decodeToken, signAccessToken, verifyAccessToken, } from './server/jwt-u
|
|
|
5
5
|
export { InMemorySessionManager } from './server/session-manager.js';
|
|
6
6
|
export { broadcastTokenRefresh, setupCrossTabSync, } from './client/cross-tab-sync.js';
|
|
7
7
|
export { refreshAccessToken, setupTokenRefreshOnExpiry, } from './client/token-refresh.js';
|
|
8
|
+
export { NativeAuthHandoff } from './server/native-handoff.js';
|
|
9
|
+
export type { NativeAuthGrant, NativeAuthGrantConsume, NativeAuthGrantStore, NativeAuthHandoffOptions } from './server/native-handoff.js';
|
|
10
|
+
export { authenticateNativeSession } from './client/native-session.js';
|
|
11
|
+
export type { NativeAccessSession, NativeSessionOptions } from './client/native-session.js';
|
|
12
|
+
export { createNativeHttpFetch } from './client/native-http.js';
|
|
13
|
+
export type { NativeHttpBridge } from './client/native-http.js';
|
package/dist/auth/index.js
CHANGED
|
@@ -6,4 +6,7 @@ export { InMemorySessionManager } from './server/session-manager.js';
|
|
|
6
6
|
// Client utilities
|
|
7
7
|
export { broadcastTokenRefresh, setupCrossTabSync, } from './client/cross-tab-sync.js';
|
|
8
8
|
export { refreshAccessToken, setupTokenRefreshOnExpiry, } from './client/token-refresh.js';
|
|
9
|
+
export { NativeAuthHandoff } from './server/native-handoff.js';
|
|
10
|
+
export { authenticateNativeSession } from './client/native-session.js';
|
|
11
|
+
export { createNativeHttpFetch } from './client/native-http.js';
|
|
9
12
|
//# sourceMappingURL=index.js.map
|
package/dist/auth/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAcA,mBAAmB;AACnB,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,qBAAqB,GACtB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EACL,WAAW,EACX,eAAe,EACf,iBAAiB,GAClB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAA;AAEjE,mBAAmB;AACnB,OAAO,EACL,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACL,kBAAkB,EAClB,yBAAyB,GAC1B,MAAM,wBAAwB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAcA,mBAAmB;AACnB,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,qBAAqB,GACtB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EACL,WAAW,EACX,eAAe,EACf,iBAAiB,GAClB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAA;AAEjE,mBAAmB;AACnB,OAAO,EACL,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACL,kBAAkB,EAClB,yBAAyB,GAC1B,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAE3D,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAA;AAEnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application-owned identity intent, bound to one native authorization attempt.
|
|
3
|
+
* Store the hash, never the plaintext authorization code or a refresh token.
|
|
4
|
+
*/
|
|
5
|
+
export interface NativeAuthGrant<T> {
|
|
6
|
+
codeHash: string;
|
|
7
|
+
challenge: string;
|
|
8
|
+
redirectUri: string;
|
|
9
|
+
expiresAt: number;
|
|
10
|
+
value: T;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Atomic consume predicate. All fields must match and expiresAt must exceed now.
|
|
14
|
+
*/
|
|
15
|
+
export interface NativeAuthGrantConsume {
|
|
16
|
+
codeHash: string;
|
|
17
|
+
challenge: string;
|
|
18
|
+
redirectUri: string;
|
|
19
|
+
now: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Durable shared storage contract for deployments with multiple server processes.
|
|
23
|
+
* consume must atomically delete and return only a grant matching every predicate;
|
|
24
|
+
* failed verification must leave the valid grant intact. Purge expired grants.
|
|
25
|
+
*/
|
|
26
|
+
export interface NativeAuthGrantStore<T> {
|
|
27
|
+
create(grant: NativeAuthGrant<T>): Promise<void>;
|
|
28
|
+
consume(request: NativeAuthGrantConsume): Promise<T | null>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Server integration for an application-authenticated browser-to-native handoff.
|
|
32
|
+
*/
|
|
33
|
+
export interface NativeAuthHandoffOptions<T> {
|
|
34
|
+
store: NativeAuthGrantStore<T>;
|
|
35
|
+
redirectUris: readonly string[];
|
|
36
|
+
now?: () => number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Issues short-lived, single-use codes protected by PKCE S256. Call authorize
|
|
40
|
+
* only after authenticating the browser user. After exchange, create a separate
|
|
41
|
+
* native session and set its refresh cookie on the exchange HTTP response.
|
|
42
|
+
* This helper does not authenticate users or register public HTTP endpoints.
|
|
43
|
+
*/
|
|
44
|
+
export declare class NativeAuthHandoff<T> {
|
|
45
|
+
private readonly options;
|
|
46
|
+
private readonly now;
|
|
47
|
+
private readonly redirectUris;
|
|
48
|
+
constructor(options: NativeAuthHandoffOptions<T>);
|
|
49
|
+
/**
|
|
50
|
+
* Validates a registered callback and S256 challenge, then persists an intent.
|
|
51
|
+
* Pass only application-authorized identity data as value.
|
|
52
|
+
*/
|
|
53
|
+
authorize(request: {
|
|
54
|
+
value: T;
|
|
55
|
+
challenge: string;
|
|
56
|
+
redirectUri: string;
|
|
57
|
+
state: string;
|
|
58
|
+
}): Promise<string>;
|
|
59
|
+
/**
|
|
60
|
+
* Consumes exactly one matching code. The verifier must never be sent through
|
|
61
|
+
* the browser redirect; receive it only in the native exchange POST body.
|
|
62
|
+
*/
|
|
63
|
+
exchange(request: {
|
|
64
|
+
code: string;
|
|
65
|
+
verifier: string;
|
|
66
|
+
redirectUri: string;
|
|
67
|
+
}): Promise<T>;
|
|
68
|
+
private validateRedirect;
|
|
69
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
const CODE_PATTERN = /^[A-Za-z0-9_-]{43}$/;
|
|
3
|
+
const VERIFIER_PATTERN = /^[A-Za-z0-9._~-]{43,128}$/;
|
|
4
|
+
const GRANT_LIFETIME_MS = 120_000;
|
|
5
|
+
/**
|
|
6
|
+
* Issues short-lived, single-use codes protected by PKCE S256. Call authorize
|
|
7
|
+
* only after authenticating the browser user. After exchange, create a separate
|
|
8
|
+
* native session and set its refresh cookie on the exchange HTTP response.
|
|
9
|
+
* This helper does not authenticate users or register public HTTP endpoints.
|
|
10
|
+
*/
|
|
11
|
+
export class NativeAuthHandoff {
|
|
12
|
+
options;
|
|
13
|
+
now;
|
|
14
|
+
redirectUris;
|
|
15
|
+
constructor(options) {
|
|
16
|
+
this.options = options;
|
|
17
|
+
this.now = options.now ?? Date.now;
|
|
18
|
+
this.redirectUris = new Set(options.redirectUris);
|
|
19
|
+
for (const uri of this.redirectUris) {
|
|
20
|
+
const url = new URL(uri);
|
|
21
|
+
if (!url.protocol.includes('.') || url.username || url.password || url.search || url.hash) {
|
|
22
|
+
throw new Error('Native redirect URI must use a reverse-domain app scheme without credentials, query or fragment');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Validates a registered callback and S256 challenge, then persists an intent.
|
|
28
|
+
* Pass only application-authorized identity data as value.
|
|
29
|
+
*/
|
|
30
|
+
async authorize(request) {
|
|
31
|
+
this.validateRedirect(request.redirectUri);
|
|
32
|
+
if (!CODE_PATTERN.test(request.challenge))
|
|
33
|
+
throw new Error('Invalid native authorization challenge');
|
|
34
|
+
if (!request.state || request.state.length > 512)
|
|
35
|
+
throw new Error('Invalid native authorization state');
|
|
36
|
+
const code = randomBytes(32).toString('base64url');
|
|
37
|
+
const codeHash = createHash('sha256').update(code).digest('hex');
|
|
38
|
+
await this.options.store.create({ codeHash, challenge: request.challenge, redirectUri: request.redirectUri, expiresAt: this.now() + GRANT_LIFETIME_MS, value: request.value });
|
|
39
|
+
const callback = new URL(request.redirectUri);
|
|
40
|
+
callback.searchParams.set('code', code);
|
|
41
|
+
callback.searchParams.set('state', request.state);
|
|
42
|
+
return callback.href;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Consumes exactly one matching code. The verifier must never be sent through
|
|
46
|
+
* the browser redirect; receive it only in the native exchange POST body.
|
|
47
|
+
*/
|
|
48
|
+
async exchange(request) {
|
|
49
|
+
this.validateRedirect(request.redirectUri);
|
|
50
|
+
if (!CODE_PATTERN.test(request.code) || !VERIFIER_PATTERN.test(request.verifier)) {
|
|
51
|
+
throw new Error('Invalid or expired native authorization code');
|
|
52
|
+
}
|
|
53
|
+
const codeHash = createHash('sha256').update(request.code).digest('hex');
|
|
54
|
+
const challenge = createHash('sha256').update(request.verifier).digest('base64url');
|
|
55
|
+
const value = await this.options.store.consume({ codeHash, challenge, redirectUri: request.redirectUri, now: this.now() });
|
|
56
|
+
if (value === null)
|
|
57
|
+
throw new Error('Invalid or expired native authorization code');
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
validateRedirect(redirectUri) {
|
|
61
|
+
if (!this.redirectUris.has(redirectUri))
|
|
62
|
+
throw new Error('Unregistered native redirect URI');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=native-handoff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-handoff.js","sourceRoot":"","sources":["../../../src/auth/server/native-handoff.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/index.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { CLI_USAGE, } from '../application/cli-arguments.js';
|
|
3
3
|
import { runCli } from './run.js';
|
|
4
|
+
import { NativeCommandInterruptedError } from '../application/native-command.js';
|
|
4
5
|
runCli(process.argv.slice(2)).catch((error) => {
|
|
6
|
+
if (error instanceof NativeCommandInterruptedError) {
|
|
7
|
+
process.exitCode = error.exitCode;
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
5
10
|
const message = error instanceof Error ? error.message : String(error);
|
|
6
11
|
console.error(message);
|
|
7
12
|
console.error(CLI_USAGE);
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAEA,OAAO,EACL,SAAS,GACV,MAAM,8BAA8B,CAAA;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAEA,OAAO,EACL,SAAS,GACV,MAAM,8BAA8B,CAAA;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,6BAA6B,EAAE,MAAM,+BAA+B,CAAA;AAE7E,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IACrD,IAAI,KAAK,YAAY,6BAA6B,EAAE,CAAC;QACnD,OAAO,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAA;QACjC,OAAM;IACR,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACtE,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IACtB,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;IACxB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAA;AACtB,CAAC,CAAC,CAAA"}
|
package/dist/cli/run.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { runNative } from '../application/native.js';
|
|
2
|
+
import { runNativeSimulator } from '../application/native-simulator.js';
|
|
1
3
|
import { runBuild } from '../application/build.js';
|
|
2
4
|
import { parseCliArguments } from '../application/cli-arguments.js';
|
|
3
5
|
import { loadApplicationConfig } from '../application/config.js';
|
|
@@ -9,7 +11,22 @@ export async function runCli(arguments_) {
|
|
|
9
11
|
const root = await findApplicationRoot(process.cwd());
|
|
10
12
|
const config = await loadApplicationConfig(root);
|
|
11
13
|
if (parsed.command === 'build') {
|
|
12
|
-
await runBuild(config);
|
|
14
|
+
await runBuild(config, parsed.target);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (parsed.command === 'native') {
|
|
18
|
+
switch (parsed.action) {
|
|
19
|
+
case 'devices':
|
|
20
|
+
case 'doctor':
|
|
21
|
+
case 'run':
|
|
22
|
+
case 'logs':
|
|
23
|
+
case 'screenshot':
|
|
24
|
+
if (!await runNativeSimulator(config, parsed))
|
|
25
|
+
process.exitCode = 1;
|
|
26
|
+
break;
|
|
27
|
+
default:
|
|
28
|
+
await runNative(config, parsed.action);
|
|
29
|
+
}
|
|
13
30
|
return;
|
|
14
31
|
}
|
|
15
32
|
if (parsed.command === 'develop') {
|
package/dist/cli/run.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAEnD,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,UAA6B;IACxD,MAAM,MAAM,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAA;IAC5C,MAAM,IAAI,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAA;IACrD,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,CAAA;IAEhD,IAAI,MAAM,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;QAC/B,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAEnD,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,UAA6B;IACxD,MAAM,MAAM,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAA;IAC5C,MAAM,IAAI,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAA;IACrD,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,CAAA;IAEhD,IAAI,MAAM,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;QAC/B,MAAM,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;QACrC,OAAM;IACR,CAAC;IAED,IAAI,MAAM,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,QAAQ,MAAM,CAAC,MAAM,EAAE,CAAC;YACtB,KAAK,SAAS,CAAC;YACf,KAAK,QAAQ,CAAC;YACd,KAAK,KAAK,CAAC;YACX,KAAK,MAAM,CAAC;YACZ,KAAK,YAAY;gBACf,IAAI,CAAC,MAAM,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC;oBAAE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAA;gBACnE,MAAK;YACP;gBACE,MAAM,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;QAC1C,CAAC;QACD,OAAM;IACR,CAAC;IAED,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,eAAe,CAAC,CAAA;QAChD,OAAM;IACR,CAAC;IAED,MAAM,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,aAAa,CAAC,CAAA;AAC5E,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Explicit backend locations for clients running outside their server origin.
|
|
3
|
+
* Paths remain owned by the protocol and application, not by these origins.
|
|
4
|
+
*/
|
|
5
|
+
export interface BackendOrigins {
|
|
6
|
+
httpOrigin: string;
|
|
7
|
+
webSocketOrigin?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Validates explicit origins without including potentially secret input in errors.
|
|
11
|
+
* The WebSocket origin defaults to the HTTP host with the corresponding scheme.
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveBackendOrigins(backend: BackendOrigins): Required<BackendOrigins>;
|
|
14
|
+
/**
|
|
15
|
+
* Fetch-compatible request boundary that native hosts can implement privately.
|
|
16
|
+
*/
|
|
17
|
+
export type HttpFetch = (url: string, options?: RequestInit) => Promise<Response>;
|