primitive-app 3.2.0-alpha.2 → 3.2.0-alpha.3
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/vite-plugin/generated-env-resolver-core.d.ts +41 -9
- package/dist/dev-tools/vite-plugin/index.cjs +3 -3
- package/dist/dev-tools/vite-plugin/index.js +99 -86
- package/dist/dev-tools/vite-plugin/primitive-env.d.ts +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.js +96 -116
- package/dist/lib-Btb-Erfh.cjs +1 -0
- package/dist/{lib-B7ZH2Pdd.js → lib-CknnILDr.js} +1 -1
- package/dist/services/JsBaoClientService.d.ts +1 -1
- package/dist/testing/index.cjs +1 -1
- package/dist/testing/index.js +1 -1
- package/package.json +2 -2
- package/dist/lib-CFnieS8T.cjs +0 -1
|
@@ -12,20 +12,39 @@
|
|
|
12
12
|
* gate if this committed copy drifts from the source. Edit the CLI file and
|
|
13
13
|
* regenerate; edits made here are overwritten.
|
|
14
14
|
*/
|
|
15
|
-
/** Schema version of
|
|
15
|
+
/** Schema version of `primitive/config.json` this core understands. */
|
|
16
16
|
export declare const PRIMITIVE_CONFIG_VERSION = 1;
|
|
17
17
|
/** Schema version of `.primitive/local.json` this core writes and reads. */
|
|
18
18
|
export declare const PRIMITIVE_LOCAL_STATE_VERSION = 1;
|
|
19
|
-
|
|
19
|
+
/**
|
|
20
|
+
* The two directories, split apart by #3153 so one name never means two
|
|
21
|
+
* things: `primitive/` is the COMMITTED tree (the config and every
|
|
22
|
+
* environment's TOML), `.primitive/` is MACHINE-LOCAL state (credentials, this
|
|
23
|
+
* machine's selection, snapshot backups) and is gitignored whole.
|
|
24
|
+
*/
|
|
25
|
+
export declare const PROJECT_TREE_DIR = "primitive";
|
|
26
|
+
export declare const PROJECT_LOCAL_STATE_DIR = ".primitive";
|
|
20
27
|
export declare const PROJECT_CONFIG_FILENAME = "config.json";
|
|
21
28
|
export declare const LOCAL_STATE_FILENAME = "local.json";
|
|
22
|
-
export declare const PROJECT_CONFIG_DISPLAY_NAME = "
|
|
29
|
+
export declare const PROJECT_CONFIG_DISPLAY_NAME = "primitive/config.json";
|
|
23
30
|
export declare const LOCAL_STATE_DISPLAY_NAME = ".primitive/local.json";
|
|
31
|
+
/** The docs-site slug of the migration procedure (#3155 publishes the page). */
|
|
32
|
+
export declare const MIGRATION_GUIDE_SLUG = "getting-started/cli-project-migration";
|
|
33
|
+
/**
|
|
34
|
+
* The one refusal for a project still holding the pre-#3153 layout.
|
|
35
|
+
*
|
|
36
|
+
* There is no fallback read: a tool that quietly read `.primitive/sync/` after
|
|
37
|
+
* the move would let a half-migrated project look healthy while push and pull
|
|
38
|
+
* disagreed about which tree is the truth. So every reader — this core, the
|
|
39
|
+
* generated Vite-plugin copy, the Swift pre-build script — stops here and names
|
|
40
|
+
* the document that says what to move where.
|
|
41
|
+
*/
|
|
42
|
+
export declare function staleLayoutMessage(detail: string): string;
|
|
24
43
|
/**
|
|
25
44
|
* Error kinds callers branch on. Every failure is one of these — no reader is
|
|
26
45
|
* ever left guessing what a broken config meant.
|
|
27
46
|
*/
|
|
28
|
-
export type PrimitiveEnvErrorKind = "missing-config" | "malformed-config" | "unsupported-version" | "corrupt-local-state" | "unknown-environment" | "no-selection" | "missing-app-id";
|
|
47
|
+
export type PrimitiveEnvErrorKind = "missing-config" | "malformed-config" | "unsupported-version" | "corrupt-local-state" | "unknown-environment" | "no-selection" | "missing-app-id" | "stale-layout";
|
|
29
48
|
export declare class PrimitiveEnvError extends Error {
|
|
30
49
|
readonly kind: PrimitiveEnvErrorKind;
|
|
31
50
|
readonly path?: string;
|
|
@@ -135,22 +154,35 @@ export interface ResolveOptions {
|
|
|
135
154
|
*/
|
|
136
155
|
export declare function deriveWsUrl(apiUrl: string): string;
|
|
137
156
|
/**
|
|
138
|
-
* Finds
|
|
157
|
+
* Finds `primitive/config.json` by walking up from `cwd`, or returns the
|
|
139
158
|
* PRIMITIVE_PROJECT_CONFIG override when it is set (and exists).
|
|
159
|
+
*
|
|
160
|
+
* The override is checked for provenance BEFORE the file is read (#3153, F2):
|
|
161
|
+
* it bypasses the walk, so without this an old-layout config could be handed
|
|
162
|
+
* straight to a reader and defeat the cutover.
|
|
163
|
+
*
|
|
164
|
+
* Every return is checked against the root it implies, not just the levels the
|
|
165
|
+
* walk passed through: this is the one function every reader goes through —
|
|
166
|
+
* `resolvePrimitiveEnv` and the CLI's own `loadProjectConfig`/`findProjectRoot`
|
|
167
|
+
* alike — so a half-migrated project must be refused HERE, or the commands that
|
|
168
|
+
* never call `resolvePrimitiveEnv` would read the new tree with the old one
|
|
169
|
+
* still beside it.
|
|
140
170
|
*/
|
|
141
171
|
export declare function findPrimitiveConfigPath(options?: {
|
|
142
172
|
cwd?: string;
|
|
143
173
|
env?: Record<string, string | undefined>;
|
|
144
174
|
}): string | null;
|
|
145
175
|
/**
|
|
146
|
-
* The project root for a config path: the parent of
|
|
176
|
+
* The project root for a config path: the parent of `primitive/`, or the
|
|
147
177
|
* containing directory when the config was pointed at directly (a fixture via
|
|
148
|
-
* PRIMITIVE_PROJECT_CONFIG, which is not inside a
|
|
178
|
+
* PRIMITIVE_PROJECT_CONFIG, which is not inside a `primitive/` directory).
|
|
149
179
|
*/
|
|
150
180
|
export declare function projectRootForConfigPath(configPath: string): string;
|
|
151
181
|
/**
|
|
152
|
-
*
|
|
153
|
-
* config
|
|
182
|
+
* Machine-local state lives under the project root's `.primitive/`, not beside
|
|
183
|
+
* the config — the config is committed now, and the two must not share a
|
|
184
|
+
* directory. A fixture-pointed bare config still gets its own `.primitive/`
|
|
185
|
+
* in its own directory, so it never picks up a real project's selection.
|
|
154
186
|
*/
|
|
155
187
|
export declare function localStatePathForConfigPath(configPath: string): string;
|
|
156
188
|
/**
|
|
@@ -65,6 +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(!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`,
|
|
69
|
-
`)}function
|
|
70
|
-
`)}function
|
|
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=`.primitive`,m=`config.json`,h=`local.json`,g=`primitive/config.json`,_=`.primitive/local.json`,v=`getting-started/cli-project-migration`;function y(e){return`${e} The Primitive configuration tree moved out of the hidden directory: the config is now ${g} and each environment's TOML is at primitive/<env>/, while .primitive/ keeps only machine-local state. Nothing is read from either tree until the project is migrated — follow ${v}.`}var b=class extends Error{kind;path;constructor(e,t,n){super(t),this.name=`PrimitiveEnvError`,this.kind=e,this.path=n}};function x(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 S(e,t){return`Environment "${e}" in ${t?`${g} (${t})`:g} has no "appId". Every environment names exactly one app — add "appId": "<app-id>" to that environment in ${g}. Find the app id in the Primitive admin UI, with 'primitive apps list' run from a directory outside this project, or as the residual "currentAppId" in .primitive/credentials.json if this environment was ever pointed at an app by the retired per-machine app selection.`}function C(e){if(typeof e==`string`)return e.trim()||void 0}function w(e){return e.startsWith(`https://`)?`wss://`+e.slice(8):e.startsWith(`http://`)?`ws://`+e.slice(7):e}function T(e){let n=(0,a.join)(e,p,m);if((0,t.existsSync)(n))throw new b(`stale-layout`,y(`${n} still exists.`),n);let r=(0,a.join)(e,p,`sync`);if((0,t.existsSync)(r))throw new b(`stale-layout`,y(`${r} still exists.`),r)}function E(e={}){let n=(e.env??process.env).PRIMITIVE_PROJECT_CONFIG;if(n){let e=(0,a.resolve)(n);if((0,a.basename)((0,a.dirname)(e))===`.primitive`)throw new b(`stale-layout`,y(`PRIMITIVE_PROJECT_CONFIG points at ${e}, inside a ${p}/ directory.`),e);return(0,t.existsSync)(e)?(T(D(e)),e):null}let r=(0,a.resolve)(e.cwd??process.cwd());for(;;){let e=(0,a.join)(r,f,m);if(T(r),(0,t.existsSync)(e))return e;let n=(0,a.dirname)(r);if(n===r)return null;r=n}}function D(e){let t=(0,a.dirname)(e);return(0,a.basename)(t)===`primitive`?(0,a.dirname)(t):t}function O(e){return(0,a.join)(D(e),p,h)}function k(e){if(!(0,t.existsSync)(e))throw new b(`missing-config`,`No ${g} found at ${e}. Run 'primitive init' to create one.`,e);let n;try{n=(0,t.readFileSync)(e,`utf-8`)}catch(t){throw new b(`malformed-config`,`Failed to read ${g} (${e}): ${t.message}`,e)}let r;try{r=JSON.parse(n)}catch(t){throw new b(`malformed-config`,`Failed to parse ${g} (${e}): ${t.message}`,e)}if(!r||typeof r!=`object`||Array.isArray(r))throw new b(`malformed-config`,`${g} (${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 b(`malformed-config`,`${g} (${e}) is missing required integer field "version".`,e);if(i.version!==1)throw new b(`unsupported-version`,`${g} (${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 b(`malformed-config`,`${g} (${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 b(`malformed-config`,`Environment "${t}" must be an object in ${g} (${e}).`,e);let r=n;if(typeof r.apiUrl!=`string`||!r.apiUrl)throw new b(`malformed-config`,`Environment "${t}" must have a non-empty "apiUrl" string in ${g} (${e}).`,e);let i=C(r.appId);if(!i)throw new b(`missing-app-id`,S(t,e),e);a[t]={apiUrl:r.apiUrl.replace(/\/$/,``),appId:i,appName:typeof r.appName==`string`?r.appName:void 0,webUrl:x(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 A(e){let n=O(e);if(!(0,t.existsSync)(n))return null;let r=e=>{throw new b(`corrupt-local-state`,`${_} (${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 j(e,t){let n=Object.keys(e.environments),r=n.join(`, `)||`(none)`,i=t.configPath?`${g} (${t.configPath})`:g,a=(n,a,o)=>{if(!e.environments[n])throw new b(`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 ${_}`);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 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)}function M(e={}){let t=e.env??process.env,n=e.configPath??E({cwd:e.cwd,env:t});if(!n)throw new b(`missing-config`,`No ${g} 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=D(n);T(r);let i=k(n),{name:a,source:o}=j(i,{explicitEnvName:e.explicitEnvName||null,envVarName:t.PRIMITIVE_ENV||null,localSelection:A(n),configPath:n}),s=i.environments[a];return{name:a,apiUrl:s.apiUrl,wsUrl:w(s.apiUrl),appId:s.appId,appName:s.appName,webUrl:s.webUrl,description:s.description,source:o,configPath:n,localStatePath:O(n),projectRoot:r}}var N=[`VITE_APP_ID`,`VITE_API_URL`,`VITE_WS_URL`,`VITE_APP_NAME`],P=`VITE_EXPECTED_PRIMITIVE_ENV`,F=new Map;function I(e,t){let n=process.env[e];n!==void 0&&n!==``&&F.get(e)!==n||(process.env[e]=t,F.set(e,t))}function L(e={}){return M({cwd:e.root,env:e.env,explicitEnvName:e.primitiveEnv??null})}function R(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 z(e,t){let n=e?.envDir;return n===!1?null:typeof n==`string`&&n!==``?(0,a.resolve)(t,n):t}function B(e,t){let n=process.env[P];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=G((0,a.join)(t,n))[P];if(e!==void 0)return{value:e,where:n}}return null}function V(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} (${P} 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 ${P} 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 H(e,t,n){let r=B(e,t);if(r&&r.value!==``&&r.value!==n.name)throw Error(V(e,r,n))}function U(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=W(u,l),f={};for(let e of N){let t=process.env[e],n=t!==void 0&&F.get(e)!==t?t:d[e];n!==void 0&&n!==``&&(f[e]=n)}let p;try{p=M({cwd:l,explicitEnvName:e.primitiveEnv??null})}catch(e){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,{};throw e}if(!(f.VITE_APP_ID&&f.VITE_API_URL)){let e=z(s,l);H(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 N){if(f[e]!==void 0){g.push(e);continue}let t=m[e];t!==void 0&&(h[`import.meta.env.${e}`]=JSON.stringify(t),I(e,t))}return I(`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(R(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=z(e,o.root),r=e?.mode??o.mode;n===o.dir&&r===o.mode||(H(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 W(e,t){let n=[`.env`,`.env.local`,`.env.${e}`,`.env.${e}.local`],r={};for(let e of n)Object.assign(r,G((0,a.join)(t,e)));return r}function G(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=b,exports.primitiveDevTools=d,exports.primitiveEnv=U,exports.resolvePrimitiveEnv=L;
|
|
@@ -63,14 +63,18 @@ export const keyboardShortcut = ${JSON.stringify(s)};
|
|
|
63
63
|
}
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
|
-
var h = "
|
|
66
|
+
var h = "primitive", g = ".primitive", _ = "config.json", v = "local.json", y = "primitive/config.json", b = ".primitive/local.json", x = "getting-started/cli-project-migration";
|
|
67
|
+
function S(e) {
|
|
68
|
+
return `${e} The Primitive configuration tree moved out of the hidden directory: the config is now ${y} and each environment's TOML is at primitive/<env>/, while .primitive/ keeps only machine-local state. Nothing is read from either tree until the project is migrated — follow ${x}.`;
|
|
69
|
+
}
|
|
70
|
+
var C = class extends Error {
|
|
67
71
|
kind;
|
|
68
72
|
path;
|
|
69
73
|
constructor(e, t, n) {
|
|
70
74
|
super(t), this.name = "PrimitiveEnvError", this.kind = e, this.path = n;
|
|
71
75
|
}
|
|
72
76
|
};
|
|
73
|
-
function
|
|
77
|
+
function w(e) {
|
|
74
78
|
if (typeof e != "string") return;
|
|
75
79
|
let t = e.trim();
|
|
76
80
|
if (!t) return;
|
|
@@ -82,68 +86,75 @@ function x(e) {
|
|
|
82
86
|
}
|
|
83
87
|
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
88
|
}
|
|
85
|
-
function
|
|
86
|
-
return `Environment "${e}" in ${t ? `${
|
|
89
|
+
function T(e, t) {
|
|
90
|
+
return `Environment "${e}" in ${t ? `${y} (${t})` : y} has no "appId". Every environment names exactly one app — add "appId": "<app-id>" to that environment in ${y}. Find the app id in the Primitive admin UI, with 'primitive apps list' run from a directory outside this project, or as the residual "currentAppId" in .primitive/credentials.json if this environment was ever pointed at an app by the retired per-machine app selection.`;
|
|
87
91
|
}
|
|
88
|
-
function
|
|
92
|
+
function E(e) {
|
|
89
93
|
if (typeof e == "string") return e.trim() || void 0;
|
|
90
94
|
}
|
|
91
|
-
function
|
|
95
|
+
function D(e) {
|
|
92
96
|
return e.startsWith("https://") ? "wss://" + e.slice(8) : e.startsWith("http://") ? "ws://" + e.slice(7) : e;
|
|
93
97
|
}
|
|
94
|
-
function
|
|
98
|
+
function O(t) {
|
|
99
|
+
let n = s(t, g, _);
|
|
100
|
+
if (e(n)) throw new C("stale-layout", S(`${n} still exists.`), n);
|
|
101
|
+
let r = s(t, g, "sync");
|
|
102
|
+
if (e(r)) throw new C("stale-layout", S(`${r} still exists.`), r);
|
|
103
|
+
}
|
|
104
|
+
function k(t = {}) {
|
|
95
105
|
let n = (t.env ?? process.env).PRIMITIVE_PROJECT_CONFIG;
|
|
96
106
|
if (n) {
|
|
97
107
|
let t = c(n);
|
|
98
|
-
|
|
108
|
+
if (a(o(t)) === ".primitive") throw new C("stale-layout", S(`PRIMITIVE_PROJECT_CONFIG points at ${t}, inside a ${g}/ directory.`), t);
|
|
109
|
+
return e(t) ? (O(A(t)), t) : null;
|
|
99
110
|
}
|
|
100
111
|
let r = c(t.cwd ?? process.cwd());
|
|
101
112
|
for (;;) {
|
|
102
|
-
let t = s(r, h,
|
|
103
|
-
if (e(t)) return t;
|
|
113
|
+
let t = s(r, h, _);
|
|
114
|
+
if (O(r), e(t)) return t;
|
|
104
115
|
let n = o(r);
|
|
105
116
|
if (n === r) return null;
|
|
106
117
|
r = n;
|
|
107
118
|
}
|
|
108
119
|
}
|
|
109
|
-
function
|
|
120
|
+
function A(e) {
|
|
110
121
|
let t = o(e);
|
|
111
|
-
return a(t) === "
|
|
122
|
+
return a(t) === "primitive" ? o(t) : t;
|
|
112
123
|
}
|
|
113
|
-
function
|
|
114
|
-
return s(
|
|
124
|
+
function j(e) {
|
|
125
|
+
return s(A(e), g, v);
|
|
115
126
|
}
|
|
116
|
-
function
|
|
117
|
-
if (!e(n)) throw new
|
|
127
|
+
function M(n) {
|
|
128
|
+
if (!e(n)) throw new C("missing-config", `No ${y} found at ${n}. Run 'primitive init' to create one.`, n);
|
|
118
129
|
let r;
|
|
119
130
|
try {
|
|
120
131
|
r = t(n, "utf-8");
|
|
121
132
|
} catch (e) {
|
|
122
|
-
throw new
|
|
133
|
+
throw new C("malformed-config", `Failed to read ${y} (${n}): ${e.message}`, n);
|
|
123
134
|
}
|
|
124
135
|
let i;
|
|
125
136
|
try {
|
|
126
137
|
i = JSON.parse(r);
|
|
127
138
|
} catch (e) {
|
|
128
|
-
throw new
|
|
139
|
+
throw new C("malformed-config", `Failed to parse ${y} (${n}): ${e.message}`, n);
|
|
129
140
|
}
|
|
130
|
-
if (!i || typeof i != "object" || Array.isArray(i)) throw new
|
|
141
|
+
if (!i || typeof i != "object" || Array.isArray(i)) throw new C("malformed-config", `${y} (${n}) must contain a JSON object at the top level.`, n);
|
|
131
142
|
let a = i;
|
|
132
|
-
if (typeof a.version != "number" || !Number.isInteger(a.version)) throw new
|
|
133
|
-
if (a.version !== 1) throw new
|
|
134
|
-
if (!a.environments || typeof a.environments != "object" || Array.isArray(a.environments)) throw new
|
|
143
|
+
if (typeof a.version != "number" || !Number.isInteger(a.version)) throw new C("malformed-config", `${y} (${n}) is missing required integer field "version".`, n);
|
|
144
|
+
if (a.version !== 1) throw new C("unsupported-version", `${y} (${n}) has version ${a.version}, but this tool understands version 1.`, n);
|
|
145
|
+
if (!a.environments || typeof a.environments != "object" || Array.isArray(a.environments)) throw new C("malformed-config", `${y} (${n}) is missing required "environments" object.`, n);
|
|
135
146
|
let o = {};
|
|
136
147
|
for (let [e, t] of Object.entries(a.environments)) {
|
|
137
|
-
if (!t || typeof t != "object" || Array.isArray(t)) throw new
|
|
148
|
+
if (!t || typeof t != "object" || Array.isArray(t)) throw new C("malformed-config", `Environment "${e}" must be an object in ${y} (${n}).`, n);
|
|
138
149
|
let r = t;
|
|
139
|
-
if (typeof r.apiUrl != "string" || !r.apiUrl) throw new
|
|
140
|
-
let i =
|
|
141
|
-
if (!i) throw new
|
|
150
|
+
if (typeof r.apiUrl != "string" || !r.apiUrl) throw new C("malformed-config", `Environment "${e}" must have a non-empty "apiUrl" string in ${y} (${n}).`, n);
|
|
151
|
+
let i = E(r.appId);
|
|
152
|
+
if (!i) throw new C("missing-app-id", T(e, n), n);
|
|
142
153
|
o[e] = {
|
|
143
154
|
apiUrl: r.apiUrl.replace(/\/$/, ""),
|
|
144
155
|
appId: i,
|
|
145
156
|
appName: typeof r.appName == "string" ? r.appName : void 0,
|
|
146
|
-
webUrl:
|
|
157
|
+
webUrl: w(r.webUrl),
|
|
147
158
|
description: typeof r.description == "string" ? r.description : void 0
|
|
148
159
|
};
|
|
149
160
|
}
|
|
@@ -153,11 +164,11 @@ function O(n) {
|
|
|
153
164
|
environments: o
|
|
154
165
|
};
|
|
155
166
|
}
|
|
156
|
-
function
|
|
157
|
-
let r =
|
|
167
|
+
function N(n) {
|
|
168
|
+
let r = j(n);
|
|
158
169
|
if (!e(r)) return null;
|
|
159
170
|
let i = (e) => {
|
|
160
|
-
throw new
|
|
171
|
+
throw new C("corrupt-local-state", `${b} (${r}) is unreadable: ${e}. Delete the file or re-run 'primitive env use <name>'.`, r);
|
|
161
172
|
}, a;
|
|
162
173
|
try {
|
|
163
174
|
a = JSON.parse(t(r, "utf-8"));
|
|
@@ -168,9 +179,9 @@ function k(n) {
|
|
|
168
179
|
let o = a.selectedEnvironment;
|
|
169
180
|
return o == null || o === "" ? null : typeof o == "string" ? o : i("\"selectedEnvironment\" must be a string");
|
|
170
181
|
}
|
|
171
|
-
function
|
|
172
|
-
let n = Object.keys(e.environments), r = n.join(", ") || "(none)", i = t.configPath ? `${
|
|
173
|
-
if (!e.environments[n]) throw new
|
|
182
|
+
function P(e, t) {
|
|
183
|
+
let n = Object.keys(e.environments), r = n.join(", ") || "(none)", i = t.configPath ? `${y} (${t.configPath})` : y, a = (n, a, o) => {
|
|
184
|
+
if (!e.environments[n]) throw new C("unknown-environment", `Environment "${n}" is not defined in ${i} (selected ${o}). Available: ${r}`, t.configPath);
|
|
174
185
|
return {
|
|
175
186
|
name: n,
|
|
176
187
|
source: a
|
|
@@ -178,60 +189,62 @@ function A(e, t) {
|
|
|
178
189
|
};
|
|
179
190
|
if (t.explicitEnvName) return a(t.explicitEnvName, "explicit", "explicitly");
|
|
180
191
|
if (t.envVarName) return a(t.envVarName, "env-var", "via PRIMITIVE_ENV");
|
|
181
|
-
if (t.localSelection) return a(t.localSelection, "local", `in ${
|
|
192
|
+
if (t.localSelection) return a(t.localSelection, "local", `in ${b}`);
|
|
182
193
|
if (e.defaultEnvironment) return a(e.defaultEnvironment, "default", "as \"defaultEnvironment\"");
|
|
183
194
|
if (n.length === 1) return {
|
|
184
195
|
name: n[0],
|
|
185
196
|
source: "sole"
|
|
186
197
|
};
|
|
187
|
-
throw n.length === 0 ? new
|
|
198
|
+
throw n.length === 0 ? new C("no-selection", `${i} has no environments defined. Run 'primitive env add <name>' or 'primitive init'.`, t.configPath) : new C("no-selection", `No environment selected. Run 'primitive env use <name>', set "defaultEnvironment" in ${i}, or export PRIMITIVE_ENV. Available: ${r}`, t.configPath);
|
|
188
199
|
}
|
|
189
|
-
function
|
|
190
|
-
let t = e.env ?? process.env, n = e.configPath ??
|
|
200
|
+
function F(e = {}) {
|
|
201
|
+
let t = e.env ?? process.env, n = e.configPath ?? k({
|
|
191
202
|
cwd: e.cwd,
|
|
192
203
|
env: t
|
|
193
204
|
});
|
|
194
|
-
if (!n) throw new
|
|
195
|
-
let r =
|
|
205
|
+
if (!n) throw new C("missing-config", `No ${y} 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.`);
|
|
206
|
+
let r = A(n);
|
|
207
|
+
O(r);
|
|
208
|
+
let i = M(n), { name: a, source: o } = P(i, {
|
|
196
209
|
explicitEnvName: e.explicitEnvName || null,
|
|
197
210
|
envVarName: t.PRIMITIVE_ENV || null,
|
|
198
|
-
localSelection:
|
|
211
|
+
localSelection: N(n),
|
|
199
212
|
configPath: n
|
|
200
|
-
}),
|
|
213
|
+
}), s = i.environments[a];
|
|
201
214
|
return {
|
|
202
|
-
name:
|
|
203
|
-
apiUrl:
|
|
204
|
-
wsUrl:
|
|
205
|
-
appId:
|
|
206
|
-
appName:
|
|
207
|
-
webUrl:
|
|
208
|
-
description:
|
|
209
|
-
source:
|
|
215
|
+
name: a,
|
|
216
|
+
apiUrl: s.apiUrl,
|
|
217
|
+
wsUrl: D(s.apiUrl),
|
|
218
|
+
appId: s.appId,
|
|
219
|
+
appName: s.appName,
|
|
220
|
+
webUrl: s.webUrl,
|
|
221
|
+
description: s.description,
|
|
222
|
+
source: o,
|
|
210
223
|
configPath: n,
|
|
211
|
-
localStatePath:
|
|
212
|
-
projectRoot:
|
|
224
|
+
localStatePath: j(n),
|
|
225
|
+
projectRoot: r
|
|
213
226
|
};
|
|
214
227
|
}
|
|
215
228
|
//#endregion
|
|
216
229
|
//#region src/dev-tools/vite-plugin/primitive-env.ts
|
|
217
|
-
var
|
|
230
|
+
var I = [
|
|
218
231
|
"VITE_APP_ID",
|
|
219
232
|
"VITE_API_URL",
|
|
220
233
|
"VITE_WS_URL",
|
|
221
234
|
"VITE_APP_NAME"
|
|
222
|
-
],
|
|
223
|
-
function
|
|
235
|
+
], L = "VITE_EXPECTED_PRIMITIVE_ENV", R = /* @__PURE__ */ new Map();
|
|
236
|
+
function z(e, t) {
|
|
224
237
|
let n = process.env[e];
|
|
225
|
-
n !== void 0 && n !== "" &&
|
|
238
|
+
n !== void 0 && n !== "" && R.get(e) !== n || (process.env[e] = t, R.set(e, t));
|
|
226
239
|
}
|
|
227
|
-
function
|
|
228
|
-
return
|
|
240
|
+
function B(e = {}) {
|
|
241
|
+
return F({
|
|
229
242
|
cwd: e.root,
|
|
230
243
|
env: e.env,
|
|
231
244
|
explicitEnvName: e.primitiveEnv ?? null
|
|
232
245
|
});
|
|
233
246
|
}
|
|
234
|
-
function
|
|
247
|
+
function V(e, t, n) {
|
|
235
248
|
let r = (e) => n.includes(e) ? " (overridden)" : "", i = [
|
|
236
249
|
`[primitive-env] Primitive environment: ${e.name} (selected: ${e.source})`,
|
|
237
250
|
`[primitive-env] apiUrl: ${t.apiUrl}${r("VITE_API_URL")}`,
|
|
@@ -242,12 +255,12 @@ function L(e, t, n) {
|
|
|
242
255
|
];
|
|
243
256
|
return n.length > 0 && i.push(`[primitive-env] overridden by the environment: ${n.join(", ")}`), i.join("\n");
|
|
244
257
|
}
|
|
245
|
-
function
|
|
258
|
+
function H(e, t) {
|
|
246
259
|
let n = e?.envDir;
|
|
247
260
|
return n === !1 ? null : typeof n == "string" && n !== "" ? c(t, n) : t;
|
|
248
261
|
}
|
|
249
|
-
function
|
|
250
|
-
let n = process.env[
|
|
262
|
+
function U(e, t) {
|
|
263
|
+
let n = process.env[L];
|
|
251
264
|
if (n !== void 0 && n !== "") return {
|
|
252
265
|
value: n,
|
|
253
266
|
where: "the process environment"
|
|
@@ -259,7 +272,7 @@ function z(e, t) {
|
|
|
259
272
|
".env.local",
|
|
260
273
|
".env"
|
|
261
274
|
]) {
|
|
262
|
-
let e =
|
|
275
|
+
let e = J(s(t, n))[L];
|
|
263
276
|
if (e !== void 0) return {
|
|
264
277
|
value: e,
|
|
265
278
|
where: n
|
|
@@ -267,47 +280,47 @@ function z(e, t) {
|
|
|
267
280
|
}
|
|
268
281
|
return null;
|
|
269
282
|
}
|
|
270
|
-
function
|
|
283
|
+
function W(e, t, n) {
|
|
271
284
|
return [
|
|
272
285
|
`[primitive-env] Wrong pair: vite mode "${e}" is declared to run against Primitive environment "${t.value}", but "${n.name}" resolved.`,
|
|
273
|
-
`[primitive-env] expected: ${t.value} (${
|
|
286
|
+
`[primitive-env] expected: ${t.value} (${L} in ${t.where})`,
|
|
274
287
|
`[primitive-env] resolved: ${n.name} (selected: ${n.source})`,
|
|
275
288
|
`[primitive-env] config: ${n.configPath}`,
|
|
276
289
|
"",
|
|
277
|
-
`Run the pair you meant — PRIMITIVE_ENV=${t.value} <command> --mode ${e}, or 'primitive env use ${t.value}' — or change/remove ${
|
|
290
|
+
`Run the pair you meant — PRIMITIVE_ENV=${t.value} <command> --mode ${e}, or 'primitive env use ${t.value}' — or change/remove ${L} in ${t.where}.`,
|
|
278
291
|
"",
|
|
279
292
|
`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.`
|
|
280
293
|
].join("\n");
|
|
281
294
|
}
|
|
282
|
-
function
|
|
283
|
-
let r =
|
|
284
|
-
if (r && r.value !== "" && r.value !== n.name) throw Error(
|
|
295
|
+
function G(e, t, n) {
|
|
296
|
+
let r = U(e, t);
|
|
297
|
+
if (r && r.value !== "" && r.value !== n.name) throw Error(W(e, r, n));
|
|
285
298
|
}
|
|
286
|
-
function
|
|
299
|
+
function K(e = {}) {
|
|
287
300
|
let t = null, n = null, r, i = [], a = !1, o = null;
|
|
288
301
|
return {
|
|
289
302
|
name: "primitive-env",
|
|
290
303
|
enforce: "pre",
|
|
291
304
|
config(s, c) {
|
|
292
305
|
a = c?.command === "serve", o = null;
|
|
293
|
-
let l = s?.root ?? process.cwd(), u = c?.mode ?? "development", d =
|
|
294
|
-
for (let e of
|
|
295
|
-
let t = process.env[e], n = t !== void 0 &&
|
|
306
|
+
let l = s?.root ?? process.cwd(), u = c?.mode ?? "development", d = q(u, l), f = {};
|
|
307
|
+
for (let e of I) {
|
|
308
|
+
let t = process.env[e], n = t !== void 0 && R.get(e) !== t ? t : d[e];
|
|
296
309
|
n !== void 0 && n !== "" && (f[e] = n);
|
|
297
310
|
}
|
|
298
311
|
let p;
|
|
299
312
|
try {
|
|
300
|
-
p =
|
|
313
|
+
p = F({
|
|
301
314
|
cwd: l,
|
|
302
315
|
explicitEnvName: e.primitiveEnv ?? null
|
|
303
316
|
});
|
|
304
317
|
} catch (e) {
|
|
305
|
-
if (e instanceof
|
|
318
|
+
if (e instanceof C && 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, {};
|
|
306
319
|
throw e;
|
|
307
320
|
}
|
|
308
321
|
if (!(f.VITE_APP_ID && f.VITE_API_URL)) {
|
|
309
|
-
let e =
|
|
310
|
-
|
|
322
|
+
let e = H(s, l);
|
|
323
|
+
G(u, e, p), o = {
|
|
311
324
|
root: l,
|
|
312
325
|
mode: u,
|
|
313
326
|
dir: e
|
|
@@ -320,25 +333,25 @@ function H(e = {}) {
|
|
|
320
333
|
VITE_WS_URL: p.wsUrl,
|
|
321
334
|
VITE_APP_NAME: p.appName
|
|
322
335
|
}, h = { "import.meta.env.VITE_PRIMITIVE_ENV": JSON.stringify(p.name) }, g = [];
|
|
323
|
-
for (let e of
|
|
336
|
+
for (let e of I) {
|
|
324
337
|
if (f[e] !== void 0) {
|
|
325
338
|
g.push(e);
|
|
326
339
|
continue;
|
|
327
340
|
}
|
|
328
341
|
let t = m[e];
|
|
329
|
-
t !== void 0 && (h[`import.meta.env.${e}`] = JSON.stringify(t),
|
|
342
|
+
t !== void 0 && (h[`import.meta.env.${e}`] = JSON.stringify(t), z(e, t));
|
|
330
343
|
}
|
|
331
|
-
return
|
|
344
|
+
return z("VITE_PRIMITIVE_ENV", p.name), i = g, n = {
|
|
332
345
|
apiUrl: f.VITE_API_URL ?? p.apiUrl,
|
|
333
346
|
wsUrl: f.VITE_WS_URL ?? p.wsUrl,
|
|
334
347
|
appId: f.VITE_APP_ID ?? p.appId,
|
|
335
348
|
appName: r
|
|
336
|
-
}, e.logResolved !== !1 && console.log(
|
|
349
|
+
}, e.logResolved !== !1 && console.log(V(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 };
|
|
337
350
|
},
|
|
338
351
|
configResolved(e) {
|
|
339
352
|
if (!o || !t) return;
|
|
340
|
-
let n =
|
|
341
|
-
n === o.dir && r === o.mode || (
|
|
353
|
+
let n = H(e, o.root), r = e?.mode ?? o.mode;
|
|
354
|
+
n === o.dir && r === o.mode || (G(r, n, t), o = {
|
|
342
355
|
root: o.root,
|
|
343
356
|
mode: r,
|
|
344
357
|
dir: n
|
|
@@ -361,17 +374,17 @@ function H(e = {}) {
|
|
|
361
374
|
}
|
|
362
375
|
};
|
|
363
376
|
}
|
|
364
|
-
function
|
|
377
|
+
function q(e, t) {
|
|
365
378
|
let n = [
|
|
366
379
|
".env",
|
|
367
380
|
".env.local",
|
|
368
381
|
`.env.${e}`,
|
|
369
382
|
`.env.${e}.local`
|
|
370
383
|
], r = {};
|
|
371
|
-
for (let e of n) Object.assign(r,
|
|
384
|
+
for (let e of n) Object.assign(r, J(s(t, e)));
|
|
372
385
|
return r;
|
|
373
386
|
}
|
|
374
|
-
function
|
|
387
|
+
function J(n) {
|
|
375
388
|
if (!e(n)) return {};
|
|
376
389
|
let r = {};
|
|
377
390
|
for (let e of t(n, "utf-8").split(/\r?\n/)) {
|
|
@@ -385,4 +398,4 @@ function W(n) {
|
|
|
385
398
|
return r;
|
|
386
399
|
}
|
|
387
400
|
//#endregion
|
|
388
|
-
export {
|
|
401
|
+
export { C as PrimitiveEnvError, m as primitiveDevTools, K as primitiveEnv, B as resolvePrimitiveEnv };
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* `primitiveEnv()` — Primitive environment configuration for a Vite app (#2873).
|
|
3
3
|
*
|
|
4
4
|
* A scaffolded app used to type its backend URL and app ID twice: once in
|
|
5
|
-
*
|
|
5
|
+
* `primitive/config.json` (which every `primitive` command reads) and again in
|
|
6
6
|
* `.env` / `.env.production`. This plugin removes the second copy. It resolves
|
|
7
7
|
* the selected Primitive environment at config time and `define`s the keys the
|
|
8
8
|
* app already reads:
|