primitive-app 3.1.0-alpha.9 → 3.2.0-alpha.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/dev-tools/document-explorer/types.d.ts +1 -1
- package/dist/dev-tools/vite-plugin/generated-env-resolver-core.d.ts +170 -0
- package/dist/dev-tools/vite-plugin/index.cjs +7 -5
- package/dist/dev-tools/vite-plugin/index.d.ts +2 -0
- package/dist/dev-tools/vite-plugin/index.js +340 -23
- package/dist/dev-tools/vite-plugin/plugin.d.ts +8 -2
- package/dist/dev-tools/vite-plugin/primitive-env.d.ts +97 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/{lib-DjHuEFvC.js → lib-B7ZH2Pdd.js} +1 -1
- package/dist/lib-CFnieS8T.cjs +1 -0
- package/dist/services/JsBaoClientService.d.ts +11 -6
- package/dist/testing/index.cjs +1 -1
- package/dist/testing/index.d.ts +7 -5
- package/dist/testing/index.js +1 -1
- package/package.json +2 -2
- package/dist/lib-CgtC-xno.cjs +0 -1
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GENERATED FILE — DO NOT EDIT BY HAND.
|
|
3
|
+
*
|
|
4
|
+
* Source of truth: `cli/src/lib/env-resolver-core.ts` (the CLI owns the
|
|
5
|
+
* environment-resolution algorithm; see issue #2873).
|
|
6
|
+
*
|
|
7
|
+
* Regenerate with:
|
|
8
|
+
* node cli/scripts/gen-primitive-env-resolver.mjs (runs at CLI prebuild)
|
|
9
|
+
*
|
|
10
|
+
* A freshness guard (`--check` mode, asserted by
|
|
11
|
+
* `cli/tests/unit/env-resolver-copy-drift-guard.test.ts`) fails the CLI unit
|
|
12
|
+
* gate if this committed copy drifts from the source. Edit the CLI file and
|
|
13
|
+
* regenerate; edits made here are overwritten.
|
|
14
|
+
*/
|
|
15
|
+
/** Schema version of `.primitive/config.json` this core understands. */
|
|
16
|
+
export declare const PRIMITIVE_CONFIG_VERSION = 1;
|
|
17
|
+
/** Schema version of `.primitive/local.json` this core writes and reads. */
|
|
18
|
+
export declare const PRIMITIVE_LOCAL_STATE_VERSION = 1;
|
|
19
|
+
export declare const PROJECT_CONFIG_DIR = ".primitive";
|
|
20
|
+
export declare const PROJECT_CONFIG_FILENAME = "config.json";
|
|
21
|
+
export declare const LOCAL_STATE_FILENAME = "local.json";
|
|
22
|
+
export declare const PROJECT_CONFIG_DISPLAY_NAME = ".primitive/config.json";
|
|
23
|
+
export declare const LOCAL_STATE_DISPLAY_NAME = ".primitive/local.json";
|
|
24
|
+
/**
|
|
25
|
+
* Error kinds callers branch on. Every failure is one of these — no reader is
|
|
26
|
+
* ever left guessing what a broken config meant.
|
|
27
|
+
*/
|
|
28
|
+
export type PrimitiveEnvErrorKind = "missing-config" | "malformed-config" | "unsupported-version" | "corrupt-local-state" | "unknown-environment" | "no-selection" | "missing-app-id";
|
|
29
|
+
export declare class PrimitiveEnvError extends Error {
|
|
30
|
+
readonly kind: PrimitiveEnvErrorKind;
|
|
31
|
+
readonly path?: string;
|
|
32
|
+
constructor(kind: PrimitiveEnvErrorKind, message: string, path?: string);
|
|
33
|
+
}
|
|
34
|
+
export interface CoreEnvironmentEntry {
|
|
35
|
+
apiUrl: string;
|
|
36
|
+
appId?: string;
|
|
37
|
+
appName?: string;
|
|
38
|
+
/**
|
|
39
|
+
* The app's web counterpart for this environment, as a normalized origin
|
|
40
|
+
* (#2982). Read through `normalizeWebOrigin`, so a value this reader carries
|
|
41
|
+
* is always an origin — see that function for why the typed read other
|
|
42
|
+
* fields get is not enough here.
|
|
43
|
+
*/
|
|
44
|
+
webUrl?: string;
|
|
45
|
+
description?: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The app's web counterpart as a normalized ORIGIN, or undefined when the
|
|
49
|
+
* value cannot be one (#2982).
|
|
50
|
+
*
|
|
51
|
+
* Unlike `appId`/`appName`, a typed read is not enough. This value is not
|
|
52
|
+
* merely carried: the Swift app points its emailed sign-in link at
|
|
53
|
+
* `<webUrl>/oauth/callback` and trusts incoming universal links from the same
|
|
54
|
+
* origin, and BOTH jobs need an origin —
|
|
55
|
+
*
|
|
56
|
+
* - https except loopback, the rule the server applies to every redirect URI
|
|
57
|
+
* (`src/auth/redirect-uri.ts`): an origin that cannot be allow-listed turns
|
|
58
|
+
* every sign-in request into a 400, and a plain-http link would carry the
|
|
59
|
+
* magic token in clear;
|
|
60
|
+
* - no path, query or fragment: the web client serves its callback on its own
|
|
61
|
+
* origin plus `/oauth/callback`, which is also the exact path the
|
|
62
|
+
* `apple-app-site-association` component claims;
|
|
63
|
+
* - no credentials, which have no business in a link that goes out by email.
|
|
64
|
+
*
|
|
65
|
+
* `primitive env add --web-url` and the project-config validation reject those
|
|
66
|
+
* shapes with a field-named error, but neither is on the path from a
|
|
67
|
+
* hand-edited `.primitive/config.json` to an Xcode build: the Swift template's
|
|
68
|
+
* pre-build script reads the file directly. So every reader that feeds
|
|
69
|
+
* `primitive.json` applies the contract, and a value that misses it is read as
|
|
70
|
+
* "this environment has no web counterpart" — code-only email, no trusted
|
|
71
|
+
* origin, nothing silently pointed at the wrong URL.
|
|
72
|
+
*
|
|
73
|
+
* The message-producing twin of this rule lives in `cli/src/lib/web-url.ts`;
|
|
74
|
+
* this file cannot import it (see COPYABILITY above), and a test pins that the
|
|
75
|
+
* two agree.
|
|
76
|
+
*/
|
|
77
|
+
export declare function normalizeWebOrigin(value: unknown): string | undefined;
|
|
78
|
+
export interface CoreProjectConfig {
|
|
79
|
+
version: number;
|
|
80
|
+
defaultEnvironment?: string;
|
|
81
|
+
environments: Record<string, CoreEnvironmentEntry>;
|
|
82
|
+
}
|
|
83
|
+
/** Which precedence step picked the environment. Printed in the build banner. */
|
|
84
|
+
export type PrimitiveEnvSource = "explicit" | "env-var" | "local" | "default" | "sole";
|
|
85
|
+
export interface ResolvedPrimitiveEnv {
|
|
86
|
+
name: string;
|
|
87
|
+
apiUrl: string;
|
|
88
|
+
/** Derived from apiUrl by scheme swap — never authored separately. */
|
|
89
|
+
wsUrl: string;
|
|
90
|
+
appId?: string;
|
|
91
|
+
appName?: string;
|
|
92
|
+
/** The app's web counterpart for the SELECTED environment, if it has one. */
|
|
93
|
+
webUrl?: string;
|
|
94
|
+
description?: string;
|
|
95
|
+
source: PrimitiveEnvSource;
|
|
96
|
+
configPath: string;
|
|
97
|
+
localStatePath: string;
|
|
98
|
+
projectRoot: string;
|
|
99
|
+
}
|
|
100
|
+
export interface ResolveOptions {
|
|
101
|
+
/** Directory to start the upward walk from. Defaults to process.cwd(). */
|
|
102
|
+
cwd?: string;
|
|
103
|
+
/** Environment variables to read. Defaults to process.env. */
|
|
104
|
+
env?: Record<string, string | undefined>;
|
|
105
|
+
/** An explicit `--env` / `--primitive-env` value, if the caller has one. */
|
|
106
|
+
explicitEnvName?: string | null;
|
|
107
|
+
/** Use this config file instead of discovering one. */
|
|
108
|
+
configPath?: string;
|
|
109
|
+
/**
|
|
110
|
+
* Identity consumers (the Vite plugin, cf-deploy, the Swift script) cannot
|
|
111
|
+
* work without an app ID; plain CLI resolution can, and always could.
|
|
112
|
+
*/
|
|
113
|
+
requireAppId?: boolean;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Derives the WebSocket URL from the API URL. Every apiUrl/wsUrl pair in
|
|
117
|
+
* practice is the same host with the scheme swapped, so it is derived rather
|
|
118
|
+
* than authored — one less thing to get out of sync.
|
|
119
|
+
*/
|
|
120
|
+
export declare function deriveWsUrl(apiUrl: string): string;
|
|
121
|
+
/**
|
|
122
|
+
* Finds `.primitive/config.json` by walking up from `cwd`, or returns the
|
|
123
|
+
* PRIMITIVE_PROJECT_CONFIG override when it is set (and exists).
|
|
124
|
+
*/
|
|
125
|
+
export declare function findPrimitiveConfigPath(options?: {
|
|
126
|
+
cwd?: string;
|
|
127
|
+
env?: Record<string, string | undefined>;
|
|
128
|
+
}): string | null;
|
|
129
|
+
/**
|
|
130
|
+
* The project root for a config path: the parent of `.primitive/`, or the
|
|
131
|
+
* containing directory when the config was pointed at directly (a fixture via
|
|
132
|
+
* PRIMITIVE_PROJECT_CONFIG, which is not inside a `.primitive/` directory).
|
|
133
|
+
*/
|
|
134
|
+
export declare function projectRootForConfigPath(configPath: string): string;
|
|
135
|
+
/**
|
|
136
|
+
* Local state lives beside the config it belongs to, so a fixture-pointed
|
|
137
|
+
* config never picks up a real project's selection and vice versa.
|
|
138
|
+
*/
|
|
139
|
+
export declare function localStatePathForConfigPath(configPath: string): string;
|
|
140
|
+
/**
|
|
141
|
+
* Reads and structurally validates `.primitive/config.json`. Throws rather
|
|
142
|
+
* than guessing: a config that cannot be understood is always louder than a
|
|
143
|
+
* silent fallback to the wrong backend.
|
|
144
|
+
*/
|
|
145
|
+
export declare function readCoreProjectConfig(configPath: string): CoreProjectConfig;
|
|
146
|
+
/**
|
|
147
|
+
* Reads this machine's selection from `.primitive/local.json`. Returns null
|
|
148
|
+
* when there is no file or no selection in it; throws when the file exists but
|
|
149
|
+
* cannot be read as the shape `primitive env use` writes.
|
|
150
|
+
*/
|
|
151
|
+
export declare function readLocalSelection(configPath: string): string | null;
|
|
152
|
+
/**
|
|
153
|
+
* Applies the precedence to an already-loaded config. Exposed separately so
|
|
154
|
+
* the CLI wrapper can run its own field-level validation first and still share
|
|
155
|
+
* one ordering with every other reader.
|
|
156
|
+
*/
|
|
157
|
+
export declare function selectEnvironmentName(config: CoreProjectConfig, options: {
|
|
158
|
+
explicitEnvName?: string | null;
|
|
159
|
+
envVarName?: string | null;
|
|
160
|
+
localSelection?: string | null;
|
|
161
|
+
configPath?: string;
|
|
162
|
+
}): {
|
|
163
|
+
name: string;
|
|
164
|
+
source: PrimitiveEnvSource;
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* The whole algorithm end to end: discover the config, read the selection,
|
|
168
|
+
* apply the precedence, derive the WebSocket URL.
|
|
169
|
+
*/
|
|
170
|
+
export declare function resolvePrimitiveEnv(options?: ResolveOptions): ResolvedPrimitiveEnv;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../rolldown-runtime-BNMv73og.cjs");let t=require("node:fs"),n=require("node:module"),r=require("glob"),i=require("path");i=e.i(i,1);async function
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../rolldown-runtime-BNMv73og.cjs");let t=require("node:fs"),n=require("node:module"),r=require("glob"),i=require("path");i=e.i(i,1);let a=require("node:path");async function o(e,t=`src/tests`,n=`**/*.primitive-test.ts`){return(await(0,r.glob)(n,{cwd:i.default.join(e,t),ignore:[`**/node_modules/**`,`**/dist/**`],absolute:!0})).map(t=>({absolutePath:t,relativePath:i.default.relative(e,t)}))}var s=`virtual:primitive-devtools`,c=`\0virtual:primitive-devtools`,l=`virtual:primitive-devtools-init`,u=`\0virtual:primitive-devtools-init`;function d(e={}){let{testsDir:r=`src/tests`,testPattern:i=`**/*.primitive-test.ts`,appName:a,enabled:d=!0,keyboardShortcut:f}=e,p=()=>(typeof a==`function`?a():a)||`Primitive App`,m,h,g=(0,t.readFileSync)((0,n.createRequire)({}.url).resolve(`vue-sonner/style.css`),`utf-8`);return{name:`primitive-devtools`,configResolved(e){m=e.root,h=e.command===`serve`},resolveId(e){if(e===s)return c;if(e===l)return u},async load(e){if(e===c)return`
|
|
2
2
|
const groups = [];
|
|
3
3
|
const loadErrors = [];
|
|
4
4
|
|
|
5
|
-
${(await
|
|
5
|
+
${(await o(m,r,i)).map((e,t)=>` try {
|
|
6
6
|
const mod${t} = await import('${e.absolutePath}');
|
|
7
7
|
const val${t} = mod${t}.default;
|
|
8
8
|
if (Array.isArray(val${t})) groups.push(...val${t});
|
|
@@ -15,9 +15,9 @@ ${(await a(p,r,i)).map((e,t)=>` try {
|
|
|
15
15
|
|
|
16
16
|
export const testGroups = groups;
|
|
17
17
|
export const testLoadErrors = loadErrors;
|
|
18
|
-
export const appName = ${JSON.stringify(
|
|
18
|
+
export const appName = ${JSON.stringify(p())};
|
|
19
19
|
export const keyboardShortcut = ${JSON.stringify(f)};
|
|
20
|
-
`;if(e===
|
|
20
|
+
`;if(e===u)return`
|
|
21
21
|
import { createApp, h } from 'vue';
|
|
22
22
|
import { createPinia } from 'pinia';
|
|
23
23
|
import { DevToolsRoot, jsBaoClientService } from 'primitive-app';
|
|
@@ -65,4 +65,6 @@ const observer = new MutationObserver(async (mutations, obs) => {
|
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
68
|
-
`},transformIndexHtml(e){if(!
|
|
68
|
+
`},transformIndexHtml(e){if(!h||!d)return e;let t=`<style data-primitive-devtools-sonner>${g}</style>`;return e.replace(`</body>`,`${t}\n<script type="module" src="/@id/__x00__virtual:primitive-devtools-init"><\/script>\n</body>`)},hotUpdate({file:e,server:t}){if(e.endsWith(`.primitive-test.ts`)){let e=t.moduleGraph.getModuleById(c);e&&(t.moduleGraph.invalidateModule(e),t.ws.send({type:`full-reload`}))}}}}var f=`.primitive`,p=`config.json`,m=`local.json`,h=`.primitive/config.json`,g=`.primitive/local.json`,_=class extends Error{kind;path;constructor(e,t,n){super(t),this.name=`PrimitiveEnvError`,this.kind=e,this.path=n}};function v(e){if(typeof e!=`string`)return;let t=e.trim();if(!t)return;let n;try{n=new URL(t)}catch{return}if(!(n.protocol!==`https:`&&n.protocol!==`http:`)&&!(n.protocol===`http:`&&n.hostname!==`localhost`&&n.hostname!==`127.0.0.1`)&&!(n.username||n.password)&&!(n.pathname!==`/`&&n.pathname!==``)&&!(n.search||n.hash))return n.origin}function y(e){return e.startsWith(`https://`)?`wss://`+e.slice(8):e.startsWith(`http://`)?`ws://`+e.slice(7):e}function b(e={}){let n=(e.env??process.env).PRIMITIVE_PROJECT_CONFIG;if(n){let e=(0,a.resolve)(n);return(0,t.existsSync)(e)?e:null}let r=(0,a.resolve)(e.cwd??process.cwd());for(;;){let e=(0,a.join)(r,f,p);if((0,t.existsSync)(e))return e;let n=(0,a.dirname)(r);if(n===r)return null;r=n}}function x(e){let t=(0,a.dirname)(e);return(0,a.basename)(t)===`.primitive`?(0,a.dirname)(t):t}function S(e){return(0,a.join)((0,a.dirname)(e),m)}function C(e){if(!(0,t.existsSync)(e))throw new _(`missing-config`,`No ${h} found at ${e}. Run 'primitive init' to create one.`,e);let n;try{n=(0,t.readFileSync)(e,`utf-8`)}catch(t){throw new _(`malformed-config`,`Failed to read ${h} (${e}): ${t.message}`,e)}let r;try{r=JSON.parse(n)}catch(t){throw new _(`malformed-config`,`Failed to parse ${h} (${e}): ${t.message}`,e)}if(!r||typeof r!=`object`||Array.isArray(r))throw new _(`malformed-config`,`${h} (${e}) must contain a JSON object at the top level.`,e);let i=r;if(typeof i.version!=`number`||!Number.isInteger(i.version))throw new _(`malformed-config`,`${h} (${e}) is missing required integer field "version".`,e);if(i.version!==1)throw new _(`unsupported-version`,`${h} (${e}) has version ${i.version}, but this tool understands version 1.`,e);if(!i.environments||typeof i.environments!=`object`||Array.isArray(i.environments))throw new _(`malformed-config`,`${h} (${e}) is missing required "environments" object.`,e);let a={};for(let[t,n]of Object.entries(i.environments)){if(!n||typeof n!=`object`||Array.isArray(n))throw new _(`malformed-config`,`Environment "${t}" must be an object in ${h} (${e}).`,e);let r=n;if(typeof r.apiUrl!=`string`||!r.apiUrl)throw new _(`malformed-config`,`Environment "${t}" must have a non-empty "apiUrl" string in ${h} (${e}).`,e);a[t]={apiUrl:r.apiUrl.replace(/\/$/,``),appId:typeof r.appId==`string`?r.appId:void 0,appName:typeof r.appName==`string`?r.appName:void 0,webUrl:v(r.webUrl),description:typeof r.description==`string`?r.description:void 0}}return{version:i.version,defaultEnvironment:typeof i.defaultEnvironment==`string`&&i.defaultEnvironment?i.defaultEnvironment:void 0,environments:a}}function w(e){let n=S(e);if(!(0,t.existsSync)(n))return null;let r=e=>{throw new _(`corrupt-local-state`,`${g} (${n}) is unreadable: ${e}. Delete the file or re-run 'primitive env use <name>'.`,n)},i;try{i=JSON.parse((0,t.readFileSync)(n,`utf-8`))}catch(e){return r(e.message)}if(!i||typeof i!=`object`||Array.isArray(i))return r(`expected a JSON object`);let a=i.selectedEnvironment;return a==null||a===``?null:typeof a==`string`?a:r(`"selectedEnvironment" must be a string`)}function T(e,t){let n=Object.keys(e.environments),r=n.join(`, `)||`(none)`,i=t.configPath?`${h} (${t.configPath})`:h,a=(n,a,o)=>{if(!e.environments[n])throw new _(`unknown-environment`,`Environment "${n}" is not defined in ${i} (selected ${o}). Available: ${r}`,t.configPath);return{name:n,source:a}};if(t.explicitEnvName)return a(t.explicitEnvName,`explicit`,`explicitly`);if(t.envVarName)return a(t.envVarName,`env-var`,`via PRIMITIVE_ENV`);if(t.localSelection)return a(t.localSelection,`local`,`in ${g}`);if(e.defaultEnvironment)return a(e.defaultEnvironment,`default`,`as "defaultEnvironment"`);if(n.length===1)return{name:n[0],source:`sole`};throw n.length===0?new _(`no-selection`,`${i} has no environments defined. Run 'primitive env add <name>' or 'primitive init'.`,t.configPath):new _(`no-selection`,`No environment selected. Run 'primitive env use <name>', set "defaultEnvironment" in ${i}, or export PRIMITIVE_ENV. Available: ${r}`,t.configPath)}function E(e={}){let t=e.env??process.env,n=e.configPath??b({cwd:e.cwd,env:t});if(!n)throw new _(`missing-config`,`No ${h} found in ${e.cwd??process.cwd()} or any parent directory. Run 'primitive init' to create one, or 'primitive env add <name>' to add an environment.`);let r=C(n),{name:i,source:a}=T(r,{explicitEnvName:e.explicitEnvName||null,envVarName:t.PRIMITIVE_ENV||null,localSelection:w(n),configPath:n}),o=r.environments[i];if(e.requireAppId&&!o.appId)throw new _(`missing-app-id`,`Environment "${i}" in ${h} (${n}) has no "appId", which this build needs. Add one with 'primitive env add ${i} --api-url ${o.apiUrl} --app-id <id>' or edit the config.`,n);return{name:i,apiUrl:o.apiUrl,wsUrl:y(o.apiUrl),appId:o.appId,appName:o.appName,webUrl:o.webUrl,description:o.description,source:a,configPath:n,localStatePath:S(n),projectRoot:x(n)}}var D=[`VITE_APP_ID`,`VITE_API_URL`,`VITE_WS_URL`,`VITE_APP_NAME`],O=`VITE_EXPECTED_PRIMITIVE_ENV`,k=new Map;function A(e,t){let n=process.env[e];n!==void 0&&n!==``&&k.get(e)!==n||(process.env[e]=t,k.set(e,t))}function j(e={}){return E({cwd:e.root,env:e.env,explicitEnvName:e.primitiveEnv??null,requireAppId:e.requireAppId})}function M(e,t,n){let r=e=>n.includes(e)?` (overridden)`:``,i=[`[primitive-env] Primitive environment: ${e.name} (selected: ${e.source})`,`[primitive-env] apiUrl: ${t.apiUrl}${r(`VITE_API_URL`)}`,`[primitive-env] wsUrl: ${t.wsUrl}${r(`VITE_WS_URL`)}`,`[primitive-env] appId: ${t.appId??`(unset)`}${r(`VITE_APP_ID`)}`,`[primitive-env] appName: ${t.appName??`(unset)`}${r(`VITE_APP_NAME`)}`,`[primitive-env] config: ${e.configPath}`];return n.length>0&&i.push(`[primitive-env] overridden by the environment: ${n.join(`, `)}`),i.join(`
|
|
69
|
+
`)}function N(e,t){let n=e?.envDir;return n===!1?null:typeof n==`string`&&n!==``?(0,a.resolve)(t,n):t}function P(e,t){let n=process.env[O];if(n!==void 0&&n!==``)return{value:n,where:`the process environment`};if(t===null)return null;for(let n of[`.env.${e}.local`,`.env.${e}`,`.env.local`,`.env`]){let e=z((0,a.join)(t,n))[O];if(e!==void 0)return{value:e,where:n}}return null}function F(e,t,n){return[`[primitive-env] Wrong pair: vite mode "${e}" is declared to run against Primitive environment "${t.value}", but "${n.name}" resolved.`,`[primitive-env] expected: ${t.value} (${O} in ${t.where})`,`[primitive-env] resolved: ${n.name} (selected: ${n.source})`,`[primitive-env] config: ${n.configPath}`,``,`Run the pair you meant — PRIMITIVE_ENV=${t.value} <command> --mode ${e}, or 'primitive env use ${t.value}' — or change/remove ${O} in ${t.where}.`,``,`A mode declares this when its .env.${e} carries values coupled to one backend, so continuing would run this environment's identity with another's configuration.`].join(`
|
|
70
|
+
`)}function I(e,t,n){let r=P(e,t);if(r&&r.value!==``&&r.value!==n.name)throw Error(F(e,r,n))}function L(e={}){let t=null,n=null,r,i=[],a=!1,o=null;return{name:`primitive-env`,enforce:`pre`,config(s,c){a=c?.command===`serve`,o=null;let l=s?.root??process.cwd(),u=c?.mode??`development`,d=R(u,l),f={};for(let e of D){let t=process.env[e],n=t!==void 0&&k.get(e)!==t?t:d[e];n!==void 0&&n!==``&&(f[e]=n)}let p;try{p=E({cwd:l,explicitEnvName:e.primitiveEnv??null,requireAppId:!f.VITE_APP_ID})}catch(e){if(e instanceof _&&e.kind===`missing-config`&&f.VITE_APP_ID&&f.VITE_API_URL)return console.warn(`[primitive-env] No .primitive/config.json found; using VITE_APP_ID / VITE_API_URL from the environment. Run 'primitive init' to make the project the source of truth.`),r=f.VITE_APP_NAME,{};throw e}if(!(f.VITE_APP_ID&&f.VITE_API_URL)){let e=N(s,l);I(u,e,p),o={root:l,mode:u,dir:e}}t=p,r=f.VITE_APP_NAME??p.appName;let m={VITE_APP_ID:p.appId,VITE_API_URL:p.apiUrl,VITE_WS_URL:p.wsUrl,VITE_APP_NAME:p.appName},h={"import.meta.env.VITE_PRIMITIVE_ENV":JSON.stringify(p.name)},g=[];for(let e of D){if(f[e]!==void 0){g.push(e);continue}let t=m[e];t!==void 0&&(h[`import.meta.env.${e}`]=JSON.stringify(t),A(e,t))}return A(`VITE_PRIMITIVE_ENV`,p.name),i=g,n={apiUrl:f.VITE_API_URL??p.apiUrl,wsUrl:f.VITE_WS_URL??p.wsUrl,appId:f.VITE_APP_ID??p.appId,appName:r},e.logResolved!==!1&&console.log(M(p,n,g)),g.length>0&&console.warn(`[primitive-env] Overridden by an explicit value in .env or the shell: ${g.join(`, `)}. Remove it to use .primitive/config.json (deploys reject these outright).`),{define:h}},configResolved(e){if(!o||!t)return;let n=N(e,o.root),r=e?.mode??o.mode;n===o.dir&&r===o.mode||(I(r,n,t),o={root:o.root,mode:r,dir:n})},transformIndexHtml(){if(!a||!t||!n)return[];let e=`%c[primitive] env=${t.name} api=${n.apiUrl} app=${n.appId??`(unset)`} (${t.configPath})`+(i.length>0?` overridden: ${i.join(`, `)}`:``);return[{tag:`script`,injectTo:`head`,children:`console.info(${JSON.stringify(e)}, "color:#888");`}]},appName(){return r},resolved(){return t}}}function R(e,t){let n=[`.env`,`.env.local`,`.env.${e}`,`.env.${e}.local`],r={};for(let e of n)Object.assign(r,z((0,a.join)(t,e)));return r}function z(e){if(!(0,t.existsSync)(e))return{};let n={};for(let r of(0,t.readFileSync)(e,`utf-8`).split(/\r?\n/)){let e=r.trim();if(!e||e.startsWith(`#`))continue;let t=e.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);if(!t)continue;let i=t[2].trim(),a=i[0],o=a===`"`||a===`'`||a==="`"?i.indexOf(a,1):-1;n[t[1]]=o===-1?i.replace(/\s+#.*$/,``).trim():i.slice(1,o)}return n}exports.PrimitiveEnvError=_,exports.primitiveDevTools=d,exports.primitiveEnv=L,exports.resolvePrimitiveEnv=j;
|
|
@@ -8,3 +8,5 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export { primitiveDevTools } from "./plugin";
|
|
10
10
|
export type { PrimitiveDevToolsOptions } from "./plugin";
|
|
11
|
+
export { primitiveEnv, resolvePrimitiveEnv, PrimitiveEnvError, } from "./primitive-env";
|
|
12
|
+
export type { PrimitiveEnvOptions, PrimitiveEnvPlugin, ResolvePrimitiveEnvOptions, ResolvedPrimitiveEnv, } from "./primitive-env";
|
|
@@ -1,38 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createRequire as
|
|
3
|
-
import { glob as
|
|
4
|
-
import
|
|
1
|
+
import { existsSync as e, readFileSync as t } from "node:fs";
|
|
2
|
+
import { createRequire as n } from "node:module";
|
|
3
|
+
import { glob as r } from "glob";
|
|
4
|
+
import i from "path";
|
|
5
|
+
import { basename as a, dirname as o, join as s, resolve as c } from "node:path";
|
|
5
6
|
//#region src/dev-tools/vite-plugin/test-discovery.ts
|
|
6
|
-
async function
|
|
7
|
-
return (await n
|
|
8
|
-
cwd:
|
|
7
|
+
async function l(e, t = "src/tests", n = "**/*.primitive-test.ts") {
|
|
8
|
+
return (await r(n, {
|
|
9
|
+
cwd: i.join(e, t),
|
|
9
10
|
ignore: ["**/node_modules/**", "**/dist/**"],
|
|
10
11
|
absolute: !0
|
|
11
12
|
})).map((t) => ({
|
|
12
13
|
absolutePath: t,
|
|
13
|
-
relativePath:
|
|
14
|
+
relativePath: i.relative(e, t)
|
|
14
15
|
}));
|
|
15
16
|
}
|
|
16
17
|
//#endregion
|
|
17
18
|
//#region src/dev-tools/vite-plugin/plugin.ts
|
|
18
|
-
var
|
|
19
|
-
function
|
|
20
|
-
let { testsDir: r = "src/tests", testPattern:
|
|
19
|
+
var u = "virtual:primitive-devtools", d = "\0virtual:primitive-devtools", f = "virtual:primitive-devtools-init", p = "\0virtual:primitive-devtools-init";
|
|
20
|
+
function m(e = {}) {
|
|
21
|
+
let { testsDir: r = "src/tests", testPattern: i = "**/*.primitive-test.ts", appName: a, enabled: o = !0, keyboardShortcut: s } = e, c = () => (typeof a == "function" ? a() : a) || "Primitive App", m, h, g = t(n(import.meta.url).resolve("vue-sonner/style.css"), "utf-8");
|
|
21
22
|
return {
|
|
22
23
|
name: "primitive-devtools",
|
|
23
24
|
configResolved(e) {
|
|
24
|
-
|
|
25
|
+
m = e.root, h = e.command === "serve";
|
|
25
26
|
},
|
|
26
27
|
resolveId(e) {
|
|
27
|
-
if (e ===
|
|
28
|
-
if (e ===
|
|
28
|
+
if (e === u) return d;
|
|
29
|
+
if (e === f) return p;
|
|
29
30
|
},
|
|
30
31
|
async load(e) {
|
|
31
|
-
if (e ===
|
|
32
|
+
if (e === d) return `
|
|
32
33
|
const groups = [];
|
|
33
34
|
const loadErrors = [];
|
|
34
35
|
|
|
35
|
-
${(await
|
|
36
|
+
${(await l(m, r, i)).map((e, t) => ` try {
|
|
36
37
|
const mod${t} = await import('${e.absolutePath}');
|
|
37
38
|
const val${t} = mod${t}.default;
|
|
38
39
|
if (Array.isArray(val${t})) groups.push(...val${t});
|
|
@@ -44,23 +45,339 @@ ${(await i(p, r, l)).map((e, t) => ` try {
|
|
|
44
45
|
|
|
45
46
|
export const testGroups = groups;
|
|
46
47
|
export const testLoadErrors = loadErrors;
|
|
47
|
-
export const appName = ${JSON.stringify(
|
|
48
|
-
export const keyboardShortcut = ${JSON.stringify(
|
|
48
|
+
export const appName = ${JSON.stringify(c())};
|
|
49
|
+
export const keyboardShortcut = ${JSON.stringify(s)};
|
|
49
50
|
`;
|
|
50
|
-
if (e ===
|
|
51
|
+
if (e === p) return "\nimport { createApp, h } from 'vue';\nimport { createPinia } from 'pinia';\nimport { DevToolsRoot, jsBaoClientService } from 'primitive-app';\nimport { testGroups, testLoadErrors, appName, keyboardShortcut } from 'virtual:primitive-devtools';\n\n// Wait for the host app to register its client on window.__primitiveAppClient\nasync function waitForAppClient() {\n return new Promise((resolve) => {\n const check = () => {\n if (window.__primitiveAppClient) {\n resolve(window.__primitiveAppClient);\n } else {\n setTimeout(check, 100);\n }\n };\n check();\n });\n}\n\n// Wait for main app to mount, then inject dev tools\nconst observer = new MutationObserver(async (mutations, obs) => {\n const appEl = document.getElementById('app');\n if (appEl && appEl.children.length > 0) {\n obs.disconnect();\n\n // Wait for the app's client to be available and link it to the debug suite\n const appClient = await waitForAppClient();\n jsBaoClientService.setExternalClient(appClient);\n\n // Create mount point for dev tools\n const devToolsMount = document.createElement('div');\n devToolsMount.id = 'primitive-devtools-root';\n document.body.appendChild(devToolsMount);\n\n // Create the dev tools app with its own Pinia instance\n // The jsBaoClientService is linked to the app's client above\n const devToolsApp = createApp({\n render() {\n return h(DevToolsRoot, { testGroups, testLoadErrors, appName, keyboardShortcut });\n }\n });\n devToolsApp.use(createPinia());\n devToolsApp.mount('#primitive-devtools-root');\n }\n});\n\nobserver.observe(document.body, { childList: true, subtree: true });\n";
|
|
51
52
|
},
|
|
52
53
|
transformIndexHtml(e) {
|
|
53
|
-
if (!
|
|
54
|
-
let t = `<style data-primitive-devtools-sonner>${
|
|
54
|
+
if (!h || !o) return e;
|
|
55
|
+
let t = `<style data-primitive-devtools-sonner>${g}</style>`;
|
|
55
56
|
return e.replace("</body>", `${t}\n<script type="module" src="/@id/__x00__virtual:primitive-devtools-init"><\/script>\n</body>`);
|
|
56
57
|
},
|
|
57
58
|
hotUpdate({ file: e, server: t }) {
|
|
58
59
|
if (e.endsWith(".primitive-test.ts")) {
|
|
59
|
-
let e = t.moduleGraph.getModuleById(
|
|
60
|
+
let e = t.moduleGraph.getModuleById(d);
|
|
60
61
|
e && (t.moduleGraph.invalidateModule(e), t.ws.send({ type: "full-reload" }));
|
|
61
62
|
}
|
|
62
63
|
}
|
|
63
64
|
};
|
|
64
65
|
}
|
|
66
|
+
var h = ".primitive", g = "config.json", _ = "local.json", v = ".primitive/config.json", y = ".primitive/local.json", b = class extends Error {
|
|
67
|
+
kind;
|
|
68
|
+
path;
|
|
69
|
+
constructor(e, t, n) {
|
|
70
|
+
super(t), this.name = "PrimitiveEnvError", this.kind = e, this.path = n;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
function x(e) {
|
|
74
|
+
if (typeof e != "string") return;
|
|
75
|
+
let t = e.trim();
|
|
76
|
+
if (!t) return;
|
|
77
|
+
let n;
|
|
78
|
+
try {
|
|
79
|
+
n = new URL(t);
|
|
80
|
+
} catch {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (!(n.protocol !== "https:" && n.protocol !== "http:") && !(n.protocol === "http:" && n.hostname !== "localhost" && n.hostname !== "127.0.0.1") && !(n.username || n.password) && !(n.pathname !== "/" && n.pathname !== "") && !(n.search || n.hash)) return n.origin;
|
|
84
|
+
}
|
|
85
|
+
function S(e) {
|
|
86
|
+
return e.startsWith("https://") ? "wss://" + e.slice(8) : e.startsWith("http://") ? "ws://" + e.slice(7) : e;
|
|
87
|
+
}
|
|
88
|
+
function C(t = {}) {
|
|
89
|
+
let n = (t.env ?? process.env).PRIMITIVE_PROJECT_CONFIG;
|
|
90
|
+
if (n) {
|
|
91
|
+
let t = c(n);
|
|
92
|
+
return e(t) ? t : null;
|
|
93
|
+
}
|
|
94
|
+
let r = c(t.cwd ?? process.cwd());
|
|
95
|
+
for (;;) {
|
|
96
|
+
let t = s(r, h, g);
|
|
97
|
+
if (e(t)) return t;
|
|
98
|
+
let n = o(r);
|
|
99
|
+
if (n === r) return null;
|
|
100
|
+
r = n;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function w(e) {
|
|
104
|
+
let t = o(e);
|
|
105
|
+
return a(t) === ".primitive" ? o(t) : t;
|
|
106
|
+
}
|
|
107
|
+
function T(e) {
|
|
108
|
+
return s(o(e), _);
|
|
109
|
+
}
|
|
110
|
+
function E(n) {
|
|
111
|
+
if (!e(n)) throw new b("missing-config", `No ${v} found at ${n}. Run 'primitive init' to create one.`, n);
|
|
112
|
+
let r;
|
|
113
|
+
try {
|
|
114
|
+
r = t(n, "utf-8");
|
|
115
|
+
} catch (e) {
|
|
116
|
+
throw new b("malformed-config", `Failed to read ${v} (${n}): ${e.message}`, n);
|
|
117
|
+
}
|
|
118
|
+
let i;
|
|
119
|
+
try {
|
|
120
|
+
i = JSON.parse(r);
|
|
121
|
+
} catch (e) {
|
|
122
|
+
throw new b("malformed-config", `Failed to parse ${v} (${n}): ${e.message}`, n);
|
|
123
|
+
}
|
|
124
|
+
if (!i || typeof i != "object" || Array.isArray(i)) throw new b("malformed-config", `${v} (${n}) must contain a JSON object at the top level.`, n);
|
|
125
|
+
let a = i;
|
|
126
|
+
if (typeof a.version != "number" || !Number.isInteger(a.version)) throw new b("malformed-config", `${v} (${n}) is missing required integer field "version".`, n);
|
|
127
|
+
if (a.version !== 1) throw new b("unsupported-version", `${v} (${n}) has version ${a.version}, but this tool understands version 1.`, n);
|
|
128
|
+
if (!a.environments || typeof a.environments != "object" || Array.isArray(a.environments)) throw new b("malformed-config", `${v} (${n}) is missing required "environments" object.`, n);
|
|
129
|
+
let o = {};
|
|
130
|
+
for (let [e, t] of Object.entries(a.environments)) {
|
|
131
|
+
if (!t || typeof t != "object" || Array.isArray(t)) throw new b("malformed-config", `Environment "${e}" must be an object in ${v} (${n}).`, n);
|
|
132
|
+
let r = t;
|
|
133
|
+
if (typeof r.apiUrl != "string" || !r.apiUrl) throw new b("malformed-config", `Environment "${e}" must have a non-empty "apiUrl" string in ${v} (${n}).`, n);
|
|
134
|
+
o[e] = {
|
|
135
|
+
apiUrl: r.apiUrl.replace(/\/$/, ""),
|
|
136
|
+
appId: typeof r.appId == "string" ? r.appId : void 0,
|
|
137
|
+
appName: typeof r.appName == "string" ? r.appName : void 0,
|
|
138
|
+
webUrl: x(r.webUrl),
|
|
139
|
+
description: typeof r.description == "string" ? r.description : void 0
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
version: a.version,
|
|
144
|
+
defaultEnvironment: typeof a.defaultEnvironment == "string" && a.defaultEnvironment ? a.defaultEnvironment : void 0,
|
|
145
|
+
environments: o
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function D(n) {
|
|
149
|
+
let r = T(n);
|
|
150
|
+
if (!e(r)) return null;
|
|
151
|
+
let i = (e) => {
|
|
152
|
+
throw new b("corrupt-local-state", `${y} (${r}) is unreadable: ${e}. Delete the file or re-run 'primitive env use <name>'.`, r);
|
|
153
|
+
}, a;
|
|
154
|
+
try {
|
|
155
|
+
a = JSON.parse(t(r, "utf-8"));
|
|
156
|
+
} catch (e) {
|
|
157
|
+
return i(e.message);
|
|
158
|
+
}
|
|
159
|
+
if (!a || typeof a != "object" || Array.isArray(a)) return i("expected a JSON object");
|
|
160
|
+
let o = a.selectedEnvironment;
|
|
161
|
+
return o == null || o === "" ? null : typeof o == "string" ? o : i("\"selectedEnvironment\" must be a string");
|
|
162
|
+
}
|
|
163
|
+
function O(e, t) {
|
|
164
|
+
let n = Object.keys(e.environments), r = n.join(", ") || "(none)", i = t.configPath ? `${v} (${t.configPath})` : v, a = (n, a, o) => {
|
|
165
|
+
if (!e.environments[n]) throw new b("unknown-environment", `Environment "${n}" is not defined in ${i} (selected ${o}). Available: ${r}`, t.configPath);
|
|
166
|
+
return {
|
|
167
|
+
name: n,
|
|
168
|
+
source: a
|
|
169
|
+
};
|
|
170
|
+
};
|
|
171
|
+
if (t.explicitEnvName) return a(t.explicitEnvName, "explicit", "explicitly");
|
|
172
|
+
if (t.envVarName) return a(t.envVarName, "env-var", "via PRIMITIVE_ENV");
|
|
173
|
+
if (t.localSelection) return a(t.localSelection, "local", `in ${y}`);
|
|
174
|
+
if (e.defaultEnvironment) return a(e.defaultEnvironment, "default", "as \"defaultEnvironment\"");
|
|
175
|
+
if (n.length === 1) return {
|
|
176
|
+
name: n[0],
|
|
177
|
+
source: "sole"
|
|
178
|
+
};
|
|
179
|
+
throw n.length === 0 ? new b("no-selection", `${i} has no environments defined. Run 'primitive env add <name>' or 'primitive init'.`, t.configPath) : new b("no-selection", `No environment selected. Run 'primitive env use <name>', set "defaultEnvironment" in ${i}, or export PRIMITIVE_ENV. Available: ${r}`, t.configPath);
|
|
180
|
+
}
|
|
181
|
+
function k(e = {}) {
|
|
182
|
+
let t = e.env ?? process.env, n = e.configPath ?? C({
|
|
183
|
+
cwd: e.cwd,
|
|
184
|
+
env: t
|
|
185
|
+
});
|
|
186
|
+
if (!n) throw new b("missing-config", `No ${v} found in ${e.cwd ?? process.cwd()} or any parent directory. Run 'primitive init' to create one, or 'primitive env add <name>' to add an environment.`);
|
|
187
|
+
let r = E(n), { name: i, source: a } = O(r, {
|
|
188
|
+
explicitEnvName: e.explicitEnvName || null,
|
|
189
|
+
envVarName: t.PRIMITIVE_ENV || null,
|
|
190
|
+
localSelection: D(n),
|
|
191
|
+
configPath: n
|
|
192
|
+
}), o = r.environments[i];
|
|
193
|
+
if (e.requireAppId && !o.appId) throw new b("missing-app-id", `Environment "${i}" in ${v} (${n}) has no "appId", which this build needs. Add one with 'primitive env add ${i} --api-url ${o.apiUrl} --app-id <id>' or edit the config.`, n);
|
|
194
|
+
return {
|
|
195
|
+
name: i,
|
|
196
|
+
apiUrl: o.apiUrl,
|
|
197
|
+
wsUrl: S(o.apiUrl),
|
|
198
|
+
appId: o.appId,
|
|
199
|
+
appName: o.appName,
|
|
200
|
+
webUrl: o.webUrl,
|
|
201
|
+
description: o.description,
|
|
202
|
+
source: a,
|
|
203
|
+
configPath: n,
|
|
204
|
+
localStatePath: T(n),
|
|
205
|
+
projectRoot: w(n)
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
//#endregion
|
|
209
|
+
//#region src/dev-tools/vite-plugin/primitive-env.ts
|
|
210
|
+
var A = [
|
|
211
|
+
"VITE_APP_ID",
|
|
212
|
+
"VITE_API_URL",
|
|
213
|
+
"VITE_WS_URL",
|
|
214
|
+
"VITE_APP_NAME"
|
|
215
|
+
], j = "VITE_EXPECTED_PRIMITIVE_ENV", M = /* @__PURE__ */ new Map();
|
|
216
|
+
function N(e, t) {
|
|
217
|
+
let n = process.env[e];
|
|
218
|
+
n !== void 0 && n !== "" && M.get(e) !== n || (process.env[e] = t, M.set(e, t));
|
|
219
|
+
}
|
|
220
|
+
function P(e = {}) {
|
|
221
|
+
return k({
|
|
222
|
+
cwd: e.root,
|
|
223
|
+
env: e.env,
|
|
224
|
+
explicitEnvName: e.primitiveEnv ?? null,
|
|
225
|
+
requireAppId: e.requireAppId
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
function F(e, t, n) {
|
|
229
|
+
let r = (e) => n.includes(e) ? " (overridden)" : "", i = [
|
|
230
|
+
`[primitive-env] Primitive environment: ${e.name} (selected: ${e.source})`,
|
|
231
|
+
`[primitive-env] apiUrl: ${t.apiUrl}${r("VITE_API_URL")}`,
|
|
232
|
+
`[primitive-env] wsUrl: ${t.wsUrl}${r("VITE_WS_URL")}`,
|
|
233
|
+
`[primitive-env] appId: ${t.appId ?? "(unset)"}${r("VITE_APP_ID")}`,
|
|
234
|
+
`[primitive-env] appName: ${t.appName ?? "(unset)"}${r("VITE_APP_NAME")}`,
|
|
235
|
+
`[primitive-env] config: ${e.configPath}`
|
|
236
|
+
];
|
|
237
|
+
return n.length > 0 && i.push(`[primitive-env] overridden by the environment: ${n.join(", ")}`), i.join("\n");
|
|
238
|
+
}
|
|
239
|
+
function I(e, t) {
|
|
240
|
+
let n = e?.envDir;
|
|
241
|
+
return n === !1 ? null : typeof n == "string" && n !== "" ? c(t, n) : t;
|
|
242
|
+
}
|
|
243
|
+
function L(e, t) {
|
|
244
|
+
let n = process.env[j];
|
|
245
|
+
if (n !== void 0 && n !== "") return {
|
|
246
|
+
value: n,
|
|
247
|
+
where: "the process environment"
|
|
248
|
+
};
|
|
249
|
+
if (t === null) return null;
|
|
250
|
+
for (let n of [
|
|
251
|
+
`.env.${e}.local`,
|
|
252
|
+
`.env.${e}`,
|
|
253
|
+
".env.local",
|
|
254
|
+
".env"
|
|
255
|
+
]) {
|
|
256
|
+
let e = H(s(t, n))[j];
|
|
257
|
+
if (e !== void 0) return {
|
|
258
|
+
value: e,
|
|
259
|
+
where: n
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
function R(e, t, n) {
|
|
265
|
+
return [
|
|
266
|
+
`[primitive-env] Wrong pair: vite mode "${e}" is declared to run against Primitive environment "${t.value}", but "${n.name}" resolved.`,
|
|
267
|
+
`[primitive-env] expected: ${t.value} (${j} in ${t.where})`,
|
|
268
|
+
`[primitive-env] resolved: ${n.name} (selected: ${n.source})`,
|
|
269
|
+
`[primitive-env] config: ${n.configPath}`,
|
|
270
|
+
"",
|
|
271
|
+
`Run the pair you meant — PRIMITIVE_ENV=${t.value} <command> --mode ${e}, or 'primitive env use ${t.value}' — or change/remove ${j} in ${t.where}.`,
|
|
272
|
+
"",
|
|
273
|
+
`A mode declares this when its .env.${e} carries values coupled to one backend, so continuing would run this environment's identity with another's configuration.`
|
|
274
|
+
].join("\n");
|
|
275
|
+
}
|
|
276
|
+
function z(e, t, n) {
|
|
277
|
+
let r = L(e, t);
|
|
278
|
+
if (r && r.value !== "" && r.value !== n.name) throw Error(R(e, r, n));
|
|
279
|
+
}
|
|
280
|
+
function B(e = {}) {
|
|
281
|
+
let t = null, n = null, r, i = [], a = !1, o = null;
|
|
282
|
+
return {
|
|
283
|
+
name: "primitive-env",
|
|
284
|
+
enforce: "pre",
|
|
285
|
+
config(s, c) {
|
|
286
|
+
a = c?.command === "serve", o = null;
|
|
287
|
+
let l = s?.root ?? process.cwd(), u = c?.mode ?? "development", d = V(u, l), f = {};
|
|
288
|
+
for (let e of A) {
|
|
289
|
+
let t = process.env[e], n = t !== void 0 && M.get(e) !== t ? t : d[e];
|
|
290
|
+
n !== void 0 && n !== "" && (f[e] = n);
|
|
291
|
+
}
|
|
292
|
+
let p;
|
|
293
|
+
try {
|
|
294
|
+
p = k({
|
|
295
|
+
cwd: l,
|
|
296
|
+
explicitEnvName: e.primitiveEnv ?? null,
|
|
297
|
+
requireAppId: !f.VITE_APP_ID
|
|
298
|
+
});
|
|
299
|
+
} catch (e) {
|
|
300
|
+
if (e instanceof b && e.kind === "missing-config" && f.VITE_APP_ID && f.VITE_API_URL) return console.warn("[primitive-env] No .primitive/config.json found; using VITE_APP_ID / VITE_API_URL from the environment. Run 'primitive init' to make the project the source of truth."), r = f.VITE_APP_NAME, {};
|
|
301
|
+
throw e;
|
|
302
|
+
}
|
|
303
|
+
if (!(f.VITE_APP_ID && f.VITE_API_URL)) {
|
|
304
|
+
let e = I(s, l);
|
|
305
|
+
z(u, e, p), o = {
|
|
306
|
+
root: l,
|
|
307
|
+
mode: u,
|
|
308
|
+
dir: e
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
t = p, r = f.VITE_APP_NAME ?? p.appName;
|
|
312
|
+
let m = {
|
|
313
|
+
VITE_APP_ID: p.appId,
|
|
314
|
+
VITE_API_URL: p.apiUrl,
|
|
315
|
+
VITE_WS_URL: p.wsUrl,
|
|
316
|
+
VITE_APP_NAME: p.appName
|
|
317
|
+
}, h = { "import.meta.env.VITE_PRIMITIVE_ENV": JSON.stringify(p.name) }, g = [];
|
|
318
|
+
for (let e of A) {
|
|
319
|
+
if (f[e] !== void 0) {
|
|
320
|
+
g.push(e);
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
let t = m[e];
|
|
324
|
+
t !== void 0 && (h[`import.meta.env.${e}`] = JSON.stringify(t), N(e, t));
|
|
325
|
+
}
|
|
326
|
+
return N("VITE_PRIMITIVE_ENV", p.name), i = g, n = {
|
|
327
|
+
apiUrl: f.VITE_API_URL ?? p.apiUrl,
|
|
328
|
+
wsUrl: f.VITE_WS_URL ?? p.wsUrl,
|
|
329
|
+
appId: f.VITE_APP_ID ?? p.appId,
|
|
330
|
+
appName: r
|
|
331
|
+
}, e.logResolved !== !1 && console.log(F(p, n, g)), g.length > 0 && console.warn(`[primitive-env] Overridden by an explicit value in .env or the shell: ${g.join(", ")}. Remove it to use .primitive/config.json (deploys reject these outright).`), { define: h };
|
|
332
|
+
},
|
|
333
|
+
configResolved(e) {
|
|
334
|
+
if (!o || !t) return;
|
|
335
|
+
let n = I(e, o.root), r = e?.mode ?? o.mode;
|
|
336
|
+
n === o.dir && r === o.mode || (z(r, n, t), o = {
|
|
337
|
+
root: o.root,
|
|
338
|
+
mode: r,
|
|
339
|
+
dir: n
|
|
340
|
+
});
|
|
341
|
+
},
|
|
342
|
+
transformIndexHtml() {
|
|
343
|
+
if (!a || !t || !n) return [];
|
|
344
|
+
let e = `%c[primitive] env=${t.name} api=${n.apiUrl} app=${n.appId ?? "(unset)"} (${t.configPath})` + (i.length > 0 ? ` overridden: ${i.join(", ")}` : "");
|
|
345
|
+
return [{
|
|
346
|
+
tag: "script",
|
|
347
|
+
injectTo: "head",
|
|
348
|
+
children: `console.info(${JSON.stringify(e)}, "color:#888");`
|
|
349
|
+
}];
|
|
350
|
+
},
|
|
351
|
+
appName() {
|
|
352
|
+
return r;
|
|
353
|
+
},
|
|
354
|
+
resolved() {
|
|
355
|
+
return t;
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
function V(e, t) {
|
|
360
|
+
let n = [
|
|
361
|
+
".env",
|
|
362
|
+
".env.local",
|
|
363
|
+
`.env.${e}`,
|
|
364
|
+
`.env.${e}.local`
|
|
365
|
+
], r = {};
|
|
366
|
+
for (let e of n) Object.assign(r, H(s(t, e)));
|
|
367
|
+
return r;
|
|
368
|
+
}
|
|
369
|
+
function H(n) {
|
|
370
|
+
if (!e(n)) return {};
|
|
371
|
+
let r = {};
|
|
372
|
+
for (let e of t(n, "utf-8").split(/\r?\n/)) {
|
|
373
|
+
let t = e.trim();
|
|
374
|
+
if (!t || t.startsWith("#")) continue;
|
|
375
|
+
let n = t.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);
|
|
376
|
+
if (!n) continue;
|
|
377
|
+
let i = n[2].trim(), a = i[0], o = a === "\"" || a === "'" || a === "`" ? i.indexOf(a, 1) : -1;
|
|
378
|
+
r[n[1]] = o === -1 ? i.replace(/\s+#.*$/, "").trim() : i.slice(1, o);
|
|
379
|
+
}
|
|
380
|
+
return r;
|
|
381
|
+
}
|
|
65
382
|
//#endregion
|
|
66
|
-
export {
|
|
383
|
+
export { b as PrimitiveEnvError, m as primitiveDevTools, B as primitiveEnv, P as resolvePrimitiveEnv };
|
|
@@ -10,9 +10,15 @@ export interface PrimitiveDevToolsOptions {
|
|
|
10
10
|
*/
|
|
11
11
|
testPattern?: string;
|
|
12
12
|
/**
|
|
13
|
-
* App name shown in the dev tools UI
|
|
13
|
+
* App name shown in the dev tools UI.
|
|
14
|
+
*
|
|
15
|
+
* May be a function, evaluated when the dev-tools module is first loaded
|
|
16
|
+
* rather than when the plugin is constructed. That is what lets the label
|
|
17
|
+
* follow `primitiveEnv()`'s resolved app name: the config file must not
|
|
18
|
+
* resolve the environment eagerly (#2873), so the name is not known yet at
|
|
19
|
+
* `vite.config.ts` evaluation time.
|
|
14
20
|
*/
|
|
15
|
-
appName?: string;
|
|
21
|
+
appName?: string | (() => string | undefined);
|
|
16
22
|
/**
|
|
17
23
|
* Whether to enable the plugin. Defaults to true in development.
|
|
18
24
|
*/
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `primitiveEnv()` — Primitive environment configuration for a Vite app (#2873).
|
|
3
|
+
*
|
|
4
|
+
* A scaffolded app used to type its backend URL and app ID twice: once in
|
|
5
|
+
* `.primitive/config.json` (which every `primitive` command reads) and again in
|
|
6
|
+
* `.env` / `.env.production`. This plugin removes the second copy. It resolves
|
|
7
|
+
* the selected Primitive environment at config time and `define`s the keys the
|
|
8
|
+
* app already reads:
|
|
9
|
+
*
|
|
10
|
+
* VITE_APP_ID VITE_API_URL VITE_WS_URL VITE_APP_NAME VITE_PRIMITIVE_ENV
|
|
11
|
+
*
|
|
12
|
+
* `src/config/envConfig.ts` is untouched — it keeps reading
|
|
13
|
+
* `import.meta.env.*`. The `.env` files shrink to app behavior
|
|
14
|
+
* (`VITE_OAUTH_REDIRECT_URI`, `VITE_ENABLE_AUTH_PROXY`, `VITE_LOG_LEVEL`).
|
|
15
|
+
*
|
|
16
|
+
* ── which environment ─────────────────────────────────────────────────────
|
|
17
|
+
* `--primitive-env` / `PRIMITIVE_ENV` → `primitive env use` (the per-machine
|
|
18
|
+
* selection in `.primitive/local.json`) → the committed `defaultEnvironment` →
|
|
19
|
+
* the sole environment. That order lives in ONE place: the generated copy of
|
|
20
|
+
* the CLI's resolver core sitting beside this file.
|
|
21
|
+
*
|
|
22
|
+
* ── pairing a mode with an environment ────────────────────────────────────
|
|
23
|
+
* The vite mode and the Primitive environment are independent axes. An app
|
|
24
|
+
* whose `.env.<mode>` carries backend-coupled values can pin the combination
|
|
25
|
+
* by declaring `VITE_EXPECTED_PRIMITIVE_ENV` in that file; a run that resolves
|
|
26
|
+
* a different environment stops here, at config time — which covers `vite
|
|
27
|
+
* dev`, `vite build`, the deploy's build, and the headless vitest suite alike.
|
|
28
|
+
* Absent declaration: the axes stay fully independent.
|
|
29
|
+
*
|
|
30
|
+
* ── the escape hatch ──────────────────────────────────────────────────────
|
|
31
|
+
* An explicit `VITE_*` identity key in a `.env` file or the process
|
|
32
|
+
* environment still wins, with a warning naming it. That keeps pure-env CI
|
|
33
|
+
* builds and legacy scaffolds working — which is also why this plugin, not
|
|
34
|
+
* `vite.config.ts`, owns the resolution: an eager top-level `resolvePrimitiveEnv()`
|
|
35
|
+
* in the config file would throw before the escape hatch could apply.
|
|
36
|
+
*/
|
|
37
|
+
import type { Plugin } from "vite";
|
|
38
|
+
import { PrimitiveEnvError, type ResolvedPrimitiveEnv } from "./generated-env-resolver-core";
|
|
39
|
+
export { PrimitiveEnvError };
|
|
40
|
+
export type { ResolvedPrimitiveEnv };
|
|
41
|
+
export interface ResolvePrimitiveEnvOptions {
|
|
42
|
+
/** Project root to resolve from. Defaults to `process.cwd()`. */
|
|
43
|
+
root?: string;
|
|
44
|
+
/** Environment variables to read. Defaults to `process.env`. */
|
|
45
|
+
env?: Record<string, string | undefined>;
|
|
46
|
+
/** An explicit environment name (e.g. from `--primitive-env`). */
|
|
47
|
+
primitiveEnv?: string | null;
|
|
48
|
+
/** Fail when the resolved environment has no `appId`. */
|
|
49
|
+
requireAppId?: boolean;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Resolves the Primitive environment for a project. A thin wrapper over the
|
|
53
|
+
* generated resolver core so callers outside this plugin (scripts, tests) get
|
|
54
|
+
* the same answer the plugin does.
|
|
55
|
+
*/
|
|
56
|
+
export declare function resolvePrimitiveEnv(options?: ResolvePrimitiveEnvOptions): ResolvedPrimitiveEnv;
|
|
57
|
+
export interface PrimitiveEnvOptions {
|
|
58
|
+
/**
|
|
59
|
+
* Override the environment to build against. Normally left unset — the
|
|
60
|
+
* selection comes from `primitive env use` or `PRIMITIVE_ENV`.
|
|
61
|
+
*/
|
|
62
|
+
primitiveEnv?: string;
|
|
63
|
+
/** Print the resolved tuple. Defaults to true. */
|
|
64
|
+
logResolved?: boolean;
|
|
65
|
+
}
|
|
66
|
+
export interface PrimitiveEnvPlugin extends Plugin {
|
|
67
|
+
/**
|
|
68
|
+
* The app name after resolution and any `.env` override — what the dev-tools
|
|
69
|
+
* label should show. Undefined until the `config` hook has run, and when
|
|
70
|
+
* neither the environment nor a `VITE_APP_NAME` supplies one.
|
|
71
|
+
*/
|
|
72
|
+
appName(): string | undefined;
|
|
73
|
+
/** The resolved environment, or null when the escape hatch applied. */
|
|
74
|
+
resolved(): ResolvedPrimitiveEnv | null;
|
|
75
|
+
}
|
|
76
|
+
export declare function primitiveEnv(options?: PrimitiveEnvOptions): PrimitiveEnvPlugin;
|
|
77
|
+
/**
|
|
78
|
+
* The `.env` files Vite would load for this mode, in Vite's own precedence
|
|
79
|
+
* order, restricted to the keys this plugin cares about.
|
|
80
|
+
*
|
|
81
|
+
* Deliberately not Vite's `loadEnv`: `vite` is not a runtime dependency of
|
|
82
|
+
* this package, and reaching for it from a consumer's install layout is the
|
|
83
|
+
* kind of resolution that works on one package manager and not the next. The
|
|
84
|
+
* reader below is the same one `cf-deploy` uses for its strict check, so the
|
|
85
|
+
* build and the deploy can never disagree about what a `.env` file says.
|
|
86
|
+
*/
|
|
87
|
+
export declare function loadDotEnv(mode: string, root: string): Record<string, string>;
|
|
88
|
+
/**
|
|
89
|
+
* Parses one `.env` file. Missing file → no keys.
|
|
90
|
+
*
|
|
91
|
+
* Quoting follows what Vite's own loader does, because a value read
|
|
92
|
+
* differently here than there is exactly the kind of disagreement this plugin
|
|
93
|
+
* exists to remove: a quoted value ends at its closing quote — a `#` inside it
|
|
94
|
+
* is content, and anything after it on the line is a comment — while an
|
|
95
|
+
* unquoted value ends at the first inline comment.
|
|
96
|
+
*/
|
|
97
|
+
export declare function parseDotEnvFile(path: string): Record<string, string>;
|
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./rolldown-runtime-BNMv73og.cjs"),t=require("./lib-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./rolldown-runtime-BNMv73og.cjs"),t=require("./lib-CFnieS8T.cjs");let n=require("vue");n=e.i(n,1);let r=require("pinia"),i=require("@vueuse/core"),a=require("js-bao");var o=`data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAAXNSR0IB2cksfwAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAutQTFRFAAAAMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzis4yvAAAAPl0Uk5TAAFXmEs8zv/GMQU5sP79nDMEJYXp5H0gABVn1s9gDAZBu/v5pzoCKpHy2+6IJhaN79lUD1/f63MSC1rX7PDQUQk7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`,s=[`title`],c=[`src`],l=`primitive-devtools-anchor`,u=`primitive-devtools-btn-styles`,d=40,f=16,p=3,m=`
|
|
2
2
|
.pdt-btn {
|
|
3
3
|
position: fixed;
|
|
4
4
|
z-index: 2147483645;
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as e, c as t, i as n, n as r, o as i, r as a, s as o, t as s } from "./lib-
|
|
1
|
+
import { a as e, c as t, i as n, n as r, o as i, r as a, s as o, t as s } from "./lib-B7ZH2Pdd.js";
|
|
2
2
|
import * as c from "vue";
|
|
3
3
|
import { Comment as l, Fragment as u, Teleport as d, camelize as f, cloneVNode as p, computed as m, createBlock as h, createCommentVNode as g, createElementBlock as _, createElementVNode as v, createTextVNode as y, createVNode as b, customRef as x, defineComponent as S, getCurrentInstance as C, getCurrentScope as w, guardReactiveProps as T, h as E, inject as D, isRef as O, isVNode as k, markRaw as A, mergeDefaults as j, mergeProps as M, nextTick as N, normalizeClass as P, normalizeProps as ee, normalizeStyle as F, onBeforeUnmount as te, onMounted as I, onScopeDispose as ne, onUnmounted as re, onUpdated as L, openBlock as R, provide as ie, reactive as z, ref as B, renderList as V, renderSlot as H, resolveDynamicComponent as ae, toDisplayString as U, toHandlerKey as oe, toRaw as se, toRef as ce, toRefs as le, toValue as ue, triggerRef as de, unref as W, useAttrs as fe, vModelSelect as pe, vModelText as me, vShow as he, watch as G, watchEffect as ge, watchPostEffect as _e, withCtx as K, withDirectives as ve, withKeys as ye, withMemo as be, withModifiers as q } from "vue";
|
|
4
4
|
import { defineStore as xe } from "pinia";
|
|
@@ -72,7 +72,7 @@ var l = new class {
|
|
|
72
72
|
oauthRedirectUri: e.oauthRedirectUri
|
|
73
73
|
});
|
|
74
74
|
let t = [];
|
|
75
|
-
(!e.appId || e.appId === "MISSING_APP_ID") && t.push("appId"), (!e.apiUrl || e.apiUrl === "MISSING_API_URL") && t.push("apiUrl"), (!e.wsUrl || e.wsUrl === "MISSING_WS_URL") && t.push("wsUrl"), (!e.oauthRedirectUri || e.oauthRedirectUri === "MISSING_OAUTH_REDIRECT_URI") && t.push("oauthRedirectUri"), t.length > 0 && (s.error("❌ Configuration validation failed!"), s.error("Missing or invalid fields:", t), s.error("This will cause OAuth and API calls to fail."), s.error("
|
|
75
|
+
(!e.appId || e.appId === "MISSING_APP_ID") && t.push("appId"), (!e.apiUrl || e.apiUrl === "MISSING_API_URL") && t.push("apiUrl"), (!e.wsUrl || e.wsUrl === "MISSING_WS_URL") && t.push("wsUrl"), (!e.oauthRedirectUri || e.oauthRedirectUri === "MISSING_OAUTH_REDIRECT_URI") && t.push("oauthRedirectUri"), t.length > 0 && (s.error("❌ Configuration validation failed!"), s.error("Missing or invalid fields:", t), s.error("This will cause OAuth and API calls to fail."), s.error("Identity (appId/apiUrl/wsUrl) comes from .primitive/config.json via the primitiveEnv() Vite plugin — check that the project has one and that an environment is selected ('primitive env use <name>'). Callback and logging settings come from your .env files.")), this.config = e;
|
|
76
76
|
}
|
|
77
77
|
getConfig() {
|
|
78
78
|
return this.config;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
let e=require("js-bao-wss-client");var t={debug:0,info:1,warn:2,error:3,none:4},n=`warn`,r=class e{#e;scope;constructor(e,t){this.#e=e,this.scope=t}get level(){return this.#e.level}set level(e){this.setLevel(e)}debug(...e){this.#t(`debug`,e)}log(...e){this.#t(`info`,e,`log`)}warn(...e){this.#t(`warn`,e)}error(...e){this.#t(`error`,e)}shouldLog(e){return t[e]>=t[this.level]}getLevel(){return this.level}setLevel(e){e in t&&(this.#e.level=e)}forScope(t){let n=t.trim(),r=n?[...this.scope,n]:this.scope;return new e(this.#e,r)}#t(e,t,n){if(!this.shouldLog(e))return;let r=n??(e===`info`?`log`:e),i=this.scope.length?`[${this.scope.join(`:`)}]`:void 0,a=i?[i,...t]:t;console[r](...a)}},i={level:n},a=new r(i,[]).forScope(`PrimitiveApp`);function o(e){i.level=e}var s=a.forScope(`JsBaoClientService`);function c(){if(typeof window>`u`)return!1;let e=window.location.hostname;return e===`localhost`||e===`127.0.0.1`||e===`[::1]`||e.endsWith(`.localhost`)||e.endsWith(`.local`)}var l=new class{client=null;clientInitializationPromise=null;config=null;initialize(e){s.debug(`Initializing with config:`,{appId:e.appId?`${e.appId.substring(0,10)}...`:`MISSING`,apiUrl:e.apiUrl,wsUrl:e.wsUrl,oauthRedirectUri:e.oauthRedirectUri});let t=[];(!e.appId||e.appId===`MISSING_APP_ID`)&&t.push(`appId`),(!e.apiUrl||e.apiUrl===`MISSING_API_URL`)&&t.push(`apiUrl`),(!e.wsUrl||e.wsUrl===`MISSING_WS_URL`)&&t.push(`wsUrl`),(!e.oauthRedirectUri||e.oauthRedirectUri===`MISSING_OAUTH_REDIRECT_URI`)&&t.push(`oauthRedirectUri`),t.length>0&&(s.error(`❌ Configuration validation failed!`),s.error(`Missing or invalid fields:`,t),s.error(`This will cause OAuth and API calls to fail.`),s.error(`Identity (appId/apiUrl/wsUrl) comes from .primitive/config.json via the primitiveEnv() Vite plugin — check that the project has one and that an environment is selected ('primitive env use <name>'). Callback and logging settings come from your .env files.`)),this.config=e}getConfig(){return this.config}async getClientAsync(){if(s.debug(`Getting client async`),this.clientInitializationPromise)return this.clientInitializationPromise;if(!this.config)throw Error(`JsBaoClientService not initialized. Call initialize() first.`);return this.clientInitializationPromise=(async()=>{s.debug(`=== INITIALIZING CLIENT ===`),s.debug(`Configuration:`,this.config);let t=await(0,e.initializeClient)(this.config);if(t.on(`status`,e=>{s.debug(`Client status changed:`,e)}),t.on(`error`,e=>{s.error(`Client error:`,e)}),this.client=t,c()&&(window.__primitiveAppClient=t,this.config?.models&&Array.isArray(this.config.models))){let e={};for(let t of this.config.models){let n=t.schema?.name;if(n){let r=n.charAt(0).toUpperCase()+n.slice(1);e[r]=t}}window.__primitiveAppModels=e,s.debug(`Registered models on window:`,Object.keys(e))}return s.debug(`=== CLIENT INITIALIZATION COMPLETE ===`),t})(),this.clientInitializationPromise}setExternalClient(e){s.debug(`Setting external client from host app`),this.client=e,this.clientInitializationPromise=Promise.resolve(e)}async clearClient(){s.debug(`Clearing client singleton...`),this.client&&(this.client.disconnect().catch(e=>{s.warn(`Background disconnect failed (this is usually harmless):`,e)}),this.client=null,this.clientInitializationPromise=null,c()&&(window.__primitiveAppClient=void 0,window.__primitiveAppModels=void 0))}};function u(e){l.initialize(e)}var d=a.forScope(`TestHarness`),f=`===TEST===`;async function p(e={}){let{networkSync:t=!1}=e,n=await l.getClientAsync(),r=`${f} ${`${Date.now()}-${Math.random().toString(36).substring(2,11)}`}`;if(t){let{metadata:e}=await n.documents.create({title:r}),t=e.documentId,{doc:i}=await n.documents.open(t);if(!i)throw Error(`[TestHarness] Failed to open synced test document`);return n.setDefaultDocumentId(t),d.debug(`Created synced test document`,{docId:t}),m.set(t,{client:n,docId:t,networkSync:!0}),{docId:t}}let{metadata:i}=await n.documents.create({title:r,localOnly:!0}),a=i.documentId,{doc:o}=await n.documents.open(a,{waitForLoad:`local`,enableNetworkSync:!1});if(!o)throw Error(`[TestHarness] Failed to open test document`);return n.setDefaultDocumentId(a),d.debug(`Created test document`,{docId:a}),m.set(a,{client:n,docId:a,networkSync:!1}),{docId:a}}var m=new Map;async function h(e){let t=m.get(e.docId);if(!t){d.warn(`destroyTestDocument called with unknown handle`,{docId:e.docId});return}m.delete(e.docId);try{t.networkSync?await t.client.documents.delete(t.docId,{forceCloseIfOpen:!0}):(await t.client.documents.close(t.docId),await t.client.documents.evict(t.docId,{force:!0}))}catch(e){d.error(`Failed to destroy test document`,{docId:t.docId,err:e})}}async function g(){try{let e=await l.getClientAsync();d.debug(`[deleteAllTestDocuments] Starting cleanup...`),await e.syncMetadata({scope:`all`});let t=(await e.me.ownedDocuments()).filter(e=>e.title?.startsWith(f));if(t.length===0)return 0;d.debug(`[deleteAllTestDocuments] Found test documents to delete`,{count:t.length});let n=0;for(let r of t)try{e.documents.isOpen(r.documentId)&&await e.documents.close(r.documentId),await e.documents.evict(r.documentId,{force:!0}),n++}catch(e){d.error(`[deleteAllTestDocuments] Failed to delete test document`,{documentId:r.documentId,err:e})}return d.debug(`[deleteAllTestDocuments] Cleanup complete`,{evictedCount:n}),n}catch(e){return d.error(`[deleteAllTestDocuments] Top-level error during cleanup`,{err:e}),0}}function _(e){return e.flatMap(e=>e.tests.map(t=>({id:t.id,name:t.name,group:e.name,environment:t.environment??e.environment,run:t.run})))}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return _}});
|
|
@@ -72,15 +72,20 @@
|
|
|
72
72
|
* const docs = await client.me.ownedDocuments();
|
|
73
73
|
* ```
|
|
74
74
|
*
|
|
75
|
-
* ###
|
|
75
|
+
* ### Where the configuration comes from
|
|
76
76
|
*
|
|
77
|
-
*
|
|
77
|
+
* `VITE_APP_ID`, `VITE_API_URL`, `VITE_WS_URL` and `VITE_APP_NAME` are NOT
|
|
78
|
+
* authored by hand. They are filled in at build time by the `primitiveEnv()`
|
|
79
|
+
* plugin (`primitive-app/vite`) from the Primitive environment selected in
|
|
80
|
+
* `.primitive/config.json` — the one place a backend URL and app ID are typed.
|
|
81
|
+
* Choose the environment with `primitive env use <name>`, or `--primitive-env`
|
|
82
|
+
* on a deploy; `VITE_WS_URL` is derived from the API URL by scheme swap.
|
|
83
|
+
*
|
|
84
|
+
* Your `.env` files carry app behavior only:
|
|
78
85
|
*
|
|
79
86
|
* ```
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* VITE_WS_URL=wss://ws.primitive.dev
|
|
83
|
-
* VITE_OAUTH_REDIRECT_URI=http://localhost:5173/auth/callback
|
|
87
|
+
* VITE_OAUTH_REDIRECT_URI=/oauth/callback
|
|
88
|
+
* VITE_ENABLE_AUTH_PROXY=false
|
|
84
89
|
* VITE_LOG_LEVEL=warn
|
|
85
90
|
* ```
|
|
86
91
|
*/
|
package/dist/testing/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../rolldown-runtime-BNMv73og.cjs"),t=require("../lib-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../rolldown-runtime-BNMv73og.cjs"),t=require("../lib-CFnieS8T.cjs");let n=require("js-bao-wss-client"),r=require("node:fs"),i=require("node:path");i=e.i(i,1);let a=require("vitest");var o=`000000`;function s(e,t,n){if(e)return e;throw Error(`[primitive-app/testing] Missing ${t}: pass it to registerPrimitiveTests() or set the ${n} environment variable.`)}function c(){let e=i.default.resolve(process.cwd(),`public/sql-wasm.wasm`);if(!(0,r.existsSync)(e)){console.warn(`[primitive-app/testing] ${e} not found — using the client's default database config. If client init fails to load sql-wasm.wasm, pass clientOptions.databaseConfig explicitly.`);return}return{type:`sqljs`,options:{locateFile:()=>e}}}async function l(e){let t=[],n=[];for(let[r,i]of Object.entries(e))try{let e=(await i())?.default;Array.isArray(e)?t.push(...e):e&&typeof e==`object`&&`tests`in e?t.push(e):n.push({file:r,error:Error(`Default export is not a TestGroup (expected { name, tests }).`)})}catch(e){n.push({file:r,error:e})}return{groups:t,failures:n}}async function u(e){let{models:r,testModules:i,otpCode:u=o,testTimeoutMs:d=6e4,clientOptions:f,cleanupTestDocuments:p=!0,failBelowFullScore:m=!0}=e,h=s(e.appId??process.env.VITE_APP_ID,`appId`,`VITE_APP_ID`),g=s(e.apiUrl??process.env.VITE_API_URL,`apiUrl`,`VITE_API_URL`),_=s(e.wsUrl??process.env.VITE_WS_URL,`wsUrl`,`VITE_WS_URL`),v=s(e.email??process.env.PRIMITIVE_TEST_EMAIL,`email`,`PRIMITIVE_TEST_EMAIL`),{groups:y,failures:b}=await l(i);for(let e of b)(0,a.describe)(e.file,()=>{(0,a.it)(`loads without errors`,()=>{throw e.error instanceof Error?e.error:Error(String(e.error))})});if(y.length===0){b.length===0&&console.warn(`[primitive-app/testing] No *.primitive-test.ts groups found — nothing to register.`);return}let x;(0,a.beforeAll)(async()=>{x=await(0,n.initializeClient)({apiUrl:g,wsUrl:_,appId:h,models:r,storageConfig:{type:`auto`},databaseConfig:c(),...f});try{await x.otpVerify(v,u)}catch(e){throw Error(`[primitive-app/testing] OTP sign-in failed for ${v}. The test bypass requires the app's testAccountBaseEmails whitelist to cover this address (and invite-only/domain/waitlist apps reject provisioning like any signup). Underlying error: ${e instanceof Error?e.message:String(e)}`)}t.o.initialize({apiUrl:g,wsUrl:_,appId:h,models:r,oauthRedirectUri:f?.oauthRedirectUri??process.env.VITE_OAUTH_REDIRECT_URI??`http://localhost/oauth/callback-unused-in-node-tests`,...f}),t.o.setExternalClient(x)},12e4),(0,a.afterAll)(async()=>{if(x){if(p)try{await t.r()}catch(e){console.warn(`[primitive-app/testing] Test-document cleanup failed:`,e)}await x.disconnect()}},6e4);for(let e of y)(0,a.describe)(e.name,()=>{for(let t of e.tests){if((t.environment??e.environment)===`browser`){a.it.skip(t.name,()=>{});continue}(0,a.it)(t.name,async()=>{let e=await t.run(e=>console.log(`[${t.id}] ${e}`));e&&console.log(`[${t.id}] ${e}`);let n=e?.match(/^(\d+)\/(\d+)\s*\((\d+(?:\.\d+)?)%\)/);if(m&&n&&Number(n[1])!==Number(n[2]))throw Error(`Scored below full marks: ${e}`)},d)}})}exports.PRIMITIVE_TEST_OTP_CODE=o,exports.registerPrimitiveTests=u;
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -20,11 +20,13 @@ export interface RegisterPrimitiveTestsOptions {
|
|
|
20
20
|
/** WebSocket endpoint URL. Defaults to `process.env.VITE_WS_URL`. */
|
|
21
21
|
wsUrl?: string;
|
|
22
22
|
/**
|
|
23
|
-
* Sign-in email for the OTP test bypass. Must
|
|
24
|
-
* `testAccountBaseEmails` whitelist
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
23
|
+
* Sign-in email for the OTP test bypass. Must be a `+primitivetest`
|
|
24
|
+
* derivative of a base on the app's `testAccountBaseEmails` whitelist
|
|
25
|
+
* (e.g. `you+primitivetest-ci@domain.com` when `you@domain.com` is
|
|
26
|
+
* whitelisted) — the bare base address itself is never a test account and
|
|
27
|
+
* always fails sign-in. Use a stable suffix per CI project so the
|
|
28
|
+
* find-or-create provisioner reuses one test user across runs. Defaults to
|
|
29
|
+
* `process.env.PRIMITIVE_TEST_EMAIL`.
|
|
28
30
|
*/
|
|
29
31
|
email?: string;
|
|
30
32
|
/** OTP code to verify with. Defaults to the "000000" test bypass. */
|
package/dist/testing/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "primitive-app",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0-alpha.0",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"author": "Primitive LLC",
|
|
6
6
|
"type": "module",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"lint": "eslint . --fix --cache",
|
|
51
51
|
"format:check": "prettier --check src/",
|
|
52
52
|
"format": "prettier --write src/",
|
|
53
|
-
"codegen": "npx js-bao-codegen
|
|
53
|
+
"codegen": "npx js-bao-codegen"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@internationalized/date": "^3.12.2",
|
package/dist/lib-CgtC-xno.cjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
let e=require("js-bao-wss-client");var t={debug:0,info:1,warn:2,error:3,none:4},n=`warn`,r=class e{#e;scope;constructor(e,t){this.#e=e,this.scope=t}get level(){return this.#e.level}set level(e){this.setLevel(e)}debug(...e){this.#t(`debug`,e)}log(...e){this.#t(`info`,e,`log`)}warn(...e){this.#t(`warn`,e)}error(...e){this.#t(`error`,e)}shouldLog(e){return t[e]>=t[this.level]}getLevel(){return this.level}setLevel(e){e in t&&(this.#e.level=e)}forScope(t){let n=t.trim(),r=n?[...this.scope,n]:this.scope;return new e(this.#e,r)}#t(e,t,n){if(!this.shouldLog(e))return;let r=n??(e===`info`?`log`:e),i=this.scope.length?`[${this.scope.join(`:`)}]`:void 0,a=i?[i,...t]:t;console[r](...a)}},i={level:n},a=new r(i,[]).forScope(`PrimitiveApp`);function o(e){i.level=e}var s=a.forScope(`JsBaoClientService`);function c(){if(typeof window>`u`)return!1;let e=window.location.hostname;return e===`localhost`||e===`127.0.0.1`||e===`[::1]`||e.endsWith(`.localhost`)||e.endsWith(`.local`)}var l=new class{client=null;clientInitializationPromise=null;config=null;initialize(e){s.debug(`Initializing with config:`,{appId:e.appId?`${e.appId.substring(0,10)}...`:`MISSING`,apiUrl:e.apiUrl,wsUrl:e.wsUrl,oauthRedirectUri:e.oauthRedirectUri});let t=[];(!e.appId||e.appId===`MISSING_APP_ID`)&&t.push(`appId`),(!e.apiUrl||e.apiUrl===`MISSING_API_URL`)&&t.push(`apiUrl`),(!e.wsUrl||e.wsUrl===`MISSING_WS_URL`)&&t.push(`wsUrl`),(!e.oauthRedirectUri||e.oauthRedirectUri===`MISSING_OAUTH_REDIRECT_URI`)&&t.push(`oauthRedirectUri`),t.length>0&&(s.error(`❌ Configuration validation failed!`),s.error(`Missing or invalid fields:`,t),s.error(`This will cause OAuth and API calls to fail.`),s.error(`Please check your .env file configuration.`)),this.config=e}getConfig(){return this.config}async getClientAsync(){if(s.debug(`Getting client async`),this.clientInitializationPromise)return this.clientInitializationPromise;if(!this.config)throw Error(`JsBaoClientService not initialized. Call initialize() first.`);return this.clientInitializationPromise=(async()=>{s.debug(`=== INITIALIZING CLIENT ===`),s.debug(`Configuration:`,this.config);let t=await(0,e.initializeClient)(this.config);if(t.on(`status`,e=>{s.debug(`Client status changed:`,e)}),t.on(`error`,e=>{s.error(`Client error:`,e)}),this.client=t,c()&&(window.__primitiveAppClient=t,this.config?.models&&Array.isArray(this.config.models))){let e={};for(let t of this.config.models){let n=t.schema?.name;if(n){let r=n.charAt(0).toUpperCase()+n.slice(1);e[r]=t}}window.__primitiveAppModels=e,s.debug(`Registered models on window:`,Object.keys(e))}return s.debug(`=== CLIENT INITIALIZATION COMPLETE ===`),t})(),this.clientInitializationPromise}setExternalClient(e){s.debug(`Setting external client from host app`),this.client=e,this.clientInitializationPromise=Promise.resolve(e)}async clearClient(){s.debug(`Clearing client singleton...`),this.client&&(this.client.disconnect().catch(e=>{s.warn(`Background disconnect failed (this is usually harmless):`,e)}),this.client=null,this.clientInitializationPromise=null,c()&&(window.__primitiveAppClient=void 0,window.__primitiveAppModels=void 0))}};function u(e){l.initialize(e)}var d=a.forScope(`TestHarness`),f=`===TEST===`;async function p(e={}){let{networkSync:t=!1}=e,n=await l.getClientAsync(),r=`${f} ${`${Date.now()}-${Math.random().toString(36).substring(2,11)}`}`;if(t){let{metadata:e}=await n.documents.create({title:r}),t=e.documentId,{doc:i}=await n.documents.open(t);if(!i)throw Error(`[TestHarness] Failed to open synced test document`);return n.setDefaultDocumentId(t),d.debug(`Created synced test document`,{docId:t}),m.set(t,{client:n,docId:t,networkSync:!0}),{docId:t}}let{metadata:i}=await n.documents.create({title:r,localOnly:!0}),a=i.documentId,{doc:o}=await n.documents.open(a,{waitForLoad:`local`,enableNetworkSync:!1});if(!o)throw Error(`[TestHarness] Failed to open test document`);return n.setDefaultDocumentId(a),d.debug(`Created test document`,{docId:a}),m.set(a,{client:n,docId:a,networkSync:!1}),{docId:a}}var m=new Map;async function h(e){let t=m.get(e.docId);if(!t){d.warn(`destroyTestDocument called with unknown handle`,{docId:e.docId});return}m.delete(e.docId);try{t.networkSync?await t.client.documents.delete(t.docId,{forceCloseIfOpen:!0}):(await t.client.documents.close(t.docId),await t.client.documents.evict(t.docId,{force:!0}))}catch(e){d.error(`Failed to destroy test document`,{docId:t.docId,err:e})}}async function g(){try{let e=await l.getClientAsync();d.debug(`[deleteAllTestDocuments] Starting cleanup...`),await e.syncMetadata({scope:`all`});let t=(await e.me.ownedDocuments()).filter(e=>e.title?.startsWith(f));if(t.length===0)return 0;d.debug(`[deleteAllTestDocuments] Found test documents to delete`,{count:t.length});let n=0;for(let r of t)try{e.documents.isOpen(r.documentId)&&await e.documents.close(r.documentId),await e.documents.evict(r.documentId,{force:!0}),n++}catch(e){d.error(`[deleteAllTestDocuments] Failed to delete test document`,{documentId:r.documentId,err:e})}return d.debug(`[deleteAllTestDocuments] Cleanup complete`,{evictedCount:n}),n}catch(e){return d.error(`[deleteAllTestDocuments] Top-level error during cleanup`,{err:e}),0}}function _(e){return e.flatMap(e=>e.tests.map(t=>({id:t.id,name:t.name,group:e.name,environment:t.environment??e.environment,run:t.run})))}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return _}});
|