primitive-admin 1.1.0-alpha.47 → 1.1.0-alpha.49
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/bin/primitive.js +2 -0
- package/dist/bin/primitive.js.map +1 -1
- package/dist/src/commands/apps.js +54 -2
- package/dist/src/commands/apps.js.map +1 -1
- package/dist/src/commands/databases.js +31 -10
- package/dist/src/commands/databases.js.map +1 -1
- package/dist/src/commands/documents.js +77 -0
- package/dist/src/commands/documents.js.map +1 -1
- package/dist/src/commands/guides.d.ts +15 -12
- package/dist/src/commands/guides.js +22 -15
- package/dist/src/commands/guides.js.map +1 -1
- package/dist/src/commands/settings.d.ts +15 -0
- package/dist/src/commands/settings.js +102 -0
- package/dist/src/commands/settings.js.map +1 -0
- package/dist/src/commands/sync-app-settings.d.ts +105 -0
- package/dist/src/commands/sync-app-settings.js +339 -0
- package/dist/src/commands/sync-app-settings.js.map +1 -0
- package/dist/src/commands/sync.d.ts +34 -19
- package/dist/src/commands/sync.js +373 -200
- package/dist/src/commands/sync.js.map +1 -1
- package/dist/src/commands/workflows.js +32 -10
- package/dist/src/commands/workflows.js.map +1 -1
- package/dist/src/lib/api-client.d.ts +2 -0
- package/dist/src/lib/api-client.js +6 -0
- package/dist/src/lib/api-client.js.map +1 -1
- package/dist/src/lib/app-settings-descriptor.d.ts +108 -0
- package/dist/src/lib/app-settings-descriptor.js +250 -0
- package/dist/src/lib/app-settings-descriptor.js.map +1 -0
- package/dist/src/lib/codegen-shared/generatedFiles.d.ts +15 -0
- package/dist/src/lib/codegen-shared/generatedFiles.js +27 -10
- package/dist/src/lib/codegen-shared/generatedFiles.js.map +1 -1
- package/dist/src/lib/db-codegen/dbGenerator.d.ts +11 -83
- package/dist/src/lib/db-codegen/dbGenerator.js +93 -556
- package/dist/src/lib/db-codegen/dbGenerator.js.map +1 -1
- package/dist/src/lib/db-codegen/dbNaming.d.ts +15 -7
- package/dist/src/lib/db-codegen/dbNaming.js +25 -13
- package/dist/src/lib/db-codegen/dbNaming.js.map +1 -1
- package/dist/src/lib/db-codegen/dbTemplates.d.ts +55 -4
- package/dist/src/lib/db-codegen/dbTemplates.js +169 -40
- package/dist/src/lib/db-codegen/dbTemplates.js.map +1 -1
- package/dist/src/lib/db-codegen/dbTypeIR.d.ts +146 -0
- package/dist/src/lib/db-codegen/dbTypeIR.js +517 -0
- package/dist/src/lib/db-codegen/dbTypeIR.js.map +1 -0
- package/dist/src/lib/db-codegen/generated-operation-def-descriptor.d.ts +101 -0
- package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js +200 -0
- package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js.map +1 -0
- package/dist/src/lib/swift-codegen/dbGenerator.d.ts +68 -0
- package/dist/src/lib/swift-codegen/dbGenerator.js +380 -0
- package/dist/src/lib/swift-codegen/dbGenerator.js.map +1 -0
- package/dist/src/lib/swift-codegen/dbSwiftTypes.d.ts +42 -0
- package/dist/src/lib/swift-codegen/dbSwiftTypes.js +100 -0
- package/dist/src/lib/swift-codegen/dbSwiftTypes.js.map +1 -0
- package/dist/src/lib/swift-codegen/generator.d.ts +84 -0
- package/dist/src/lib/swift-codegen/generator.js +178 -0
- package/dist/src/lib/swift-codegen/generator.js.map +1 -0
- package/dist/src/lib/swift-codegen/schemaToSwift.d.ts +72 -0
- package/dist/src/lib/swift-codegen/schemaToSwift.js +644 -0
- package/dist/src/lib/swift-codegen/schemaToSwift.js.map +1 -0
- package/dist/src/lib/swift-codegen/swiftNaming.d.ts +85 -0
- package/dist/src/lib/swift-codegen/swiftNaming.js +198 -0
- package/dist/src/lib/swift-codegen/swiftNaming.js.map +1 -0
- package/dist/src/lib/sync-resource-types.d.ts +225 -0
- package/dist/src/lib/sync-resource-types.js +394 -0
- package/dist/src/lib/sync-resource-types.js.map +1 -0
- package/dist/src/lib/template.d.ts +1 -1
- package/dist/src/lib/template.js +6 -3
- package/dist/src/lib/template.js.map +1 -1
- package/dist/src/lib/workflow-codegen/generator.d.ts +18 -5
- package/dist/src/lib/workflow-codegen/generator.js +116 -41
- package/dist/src/lib/workflow-codegen/generator.js.map +1 -1
- package/dist/src/lib/workflow-codegen/invokerIR.d.ts +85 -0
- package/dist/src/lib/workflow-codegen/invokerIR.js +71 -0
- package/dist/src/lib/workflow-codegen/invokerIR.js.map +1 -0
- package/package.json +4 -2
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared app-settings sync helpers (issue #1033, Phase 2).
|
|
3
|
+
*
|
|
4
|
+
* The descriptor-driven `app.toml` round-trip (issue #1033, Phase 1) was born
|
|
5
|
+
* inside the big `sync pull` / `sync push` command flow. Phase 2 lifts the
|
|
6
|
+
* app-settings-specific pieces here so BOTH surfaces drive them:
|
|
7
|
+
*
|
|
8
|
+
* - `sync pull` / `sync push` call the low-level helpers
|
|
9
|
+
* (`serializeAppSettings`, `collectAppSettingsPushErrors`) — behavior
|
|
10
|
+
* unchanged from Phase 1.
|
|
11
|
+
* - the new `primitive settings show|pull|push|diff` command
|
|
12
|
+
* (`cli/src/commands/settings.ts`) calls the higher-level orchestrators
|
|
13
|
+
* (`pullAppSettings`, `pushAppSettings`, `diffAppSettings`, `showAppSettings`).
|
|
14
|
+
*
|
|
15
|
+
* Both directions share the same `app.toml`, the same field descriptor
|
|
16
|
+
* (`cli/src/lib/app-settings-descriptor.ts`), and the same single
|
|
17
|
+
* `entities.app.contentHash` sync-state entry, so `settings push` then
|
|
18
|
+
* `sync push` (or the reverse) is idempotent — the second one skips on the
|
|
19
|
+
* unchanged hash.
|
|
20
|
+
*
|
|
21
|
+
* `googleClientSecret` never leaves the server through here: pull omits it,
|
|
22
|
+
* push errors on it (pointing at `primitive apps update --google-client-secret`),
|
|
23
|
+
* and `settings show` redacts it in both the rendered and `--json` views.
|
|
24
|
+
*/
|
|
25
|
+
import type { ApiClient } from "../lib/api-client.js";
|
|
26
|
+
import { type AppSettingSection } from "../lib/app-settings-descriptor.js";
|
|
27
|
+
/** The app-settings file name inside a sync directory. */
|
|
28
|
+
export declare const APP_TOML_FILENAME = "app.toml";
|
|
29
|
+
/** Absolute path to `app.toml` inside a sync directory. */
|
|
30
|
+
export declare function appTomlPath(configDir: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* Serialize server settings into the `app.toml` string (pull direction).
|
|
33
|
+
* Descriptor-driven; `googleClientSecret` is never emitted. This is the single
|
|
34
|
+
* serializer both `sync pull` and `settings pull` use.
|
|
35
|
+
*/
|
|
36
|
+
export declare function serializeAppSettings(settings: any): string;
|
|
37
|
+
/**
|
|
38
|
+
* Write `app.toml` from server settings and return its content hash. Shared by
|
|
39
|
+
* `sync pull` and `settings pull` so the two produce byte-identical files and
|
|
40
|
+
* the same hash.
|
|
41
|
+
*/
|
|
42
|
+
export declare function writeAppSettingsToml(configDir: string, settings: any): string;
|
|
43
|
+
/**
|
|
44
|
+
* Validate a parsed `app.toml` for push and return the fatal errors (a
|
|
45
|
+
* hand-added secret key, a type mismatch). An empty array means the push may
|
|
46
|
+
* proceed. Warnings (unrecognized keys) are intentionally not returned here —
|
|
47
|
+
* the caller surfaces those at apply time. Shared by the `sync push` preflight
|
|
48
|
+
* and `settings push`.
|
|
49
|
+
*/
|
|
50
|
+
export declare function collectAppSettingsPushErrors(tomlData: Record<string, any>, options?: {
|
|
51
|
+
isCrossAppPush?: boolean;
|
|
52
|
+
}): string[];
|
|
53
|
+
/** Placeholder shown in `settings show` in place of any secret field value. */
|
|
54
|
+
export declare const REDACTED_PLACEHOLDER = "[redacted \u2014 set via: primitive apps update <appId> --google-client-secret]";
|
|
55
|
+
/**
|
|
56
|
+
* Return a copy of the server settings with every secret descriptor field
|
|
57
|
+
* (currently `googleClientSecret`) redacted when it holds a value. `null`/empty
|
|
58
|
+
* values are left untouched — there is no secret to hide. Used for BOTH the
|
|
59
|
+
* rendered and `--json` outputs of `settings show` so the real secret never
|
|
60
|
+
* leaves the server through this command (codex design-review concern #2).
|
|
61
|
+
*/
|
|
62
|
+
export declare function redactSecretFields(settings: Record<string, any>): Record<string, any>;
|
|
63
|
+
/**
|
|
64
|
+
* `settings show` — render the current server-effective settings grouped by
|
|
65
|
+
* `app.toml` section, with `googleClientSecret` redacted. `--json` emits the
|
|
66
|
+
* full (redacted) server response.
|
|
67
|
+
*/
|
|
68
|
+
export declare function showAppSettings(client: ApiClient, appId: string, options?: {
|
|
69
|
+
json?: boolean;
|
|
70
|
+
}): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* `settings pull` — fetch the server settings, write `app.toml`, and stamp the
|
|
73
|
+
* shared `entities.app.contentHash`. Same file and hash as `sync pull`.
|
|
74
|
+
*/
|
|
75
|
+
export declare function pullAppSettings(client: ApiClient, appId: string, configDir: string, options?: {
|
|
76
|
+
json?: boolean;
|
|
77
|
+
}): Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* `settings push` — read `app.toml`, validate (abort before any PUT on a secret
|
|
80
|
+
* key or a type mismatch), skip when unchanged since the last sync unless
|
|
81
|
+
* `--force`, then apply via `PUT /settings` and re-stamp the shared content
|
|
82
|
+
* hash. Cross-app pushes (state's app differs from the target) always apply and
|
|
83
|
+
* strip `name`, matching `sync push`.
|
|
84
|
+
*/
|
|
85
|
+
export declare function pushAppSettings(client: ApiClient, appId: string, configDir: string, options?: {
|
|
86
|
+
json?: boolean;
|
|
87
|
+
force?: boolean;
|
|
88
|
+
dryRun?: boolean;
|
|
89
|
+
}): Promise<void>;
|
|
90
|
+
export interface AppSettingsFieldDiff {
|
|
91
|
+
field: string;
|
|
92
|
+
section: AppSettingSection;
|
|
93
|
+
key: string;
|
|
94
|
+
local: unknown;
|
|
95
|
+
remote: unknown;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* `settings diff` — report per-field differences between the local `app.toml`
|
|
99
|
+
* push payload and the current server settings. Only keys present in the TOML
|
|
100
|
+
* are compared, so a server value that equals a descriptor default (and is
|
|
101
|
+
* therefore omitted from `app.toml`) is never flagged as a spurious difference.
|
|
102
|
+
*/
|
|
103
|
+
export declare function diffAppSettings(client: ApiClient, appId: string, configDir: string, options?: {
|
|
104
|
+
json?: boolean;
|
|
105
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared app-settings sync helpers (issue #1033, Phase 2).
|
|
3
|
+
*
|
|
4
|
+
* The descriptor-driven `app.toml` round-trip (issue #1033, Phase 1) was born
|
|
5
|
+
* inside the big `sync pull` / `sync push` command flow. Phase 2 lifts the
|
|
6
|
+
* app-settings-specific pieces here so BOTH surfaces drive them:
|
|
7
|
+
*
|
|
8
|
+
* - `sync pull` / `sync push` call the low-level helpers
|
|
9
|
+
* (`serializeAppSettings`, `collectAppSettingsPushErrors`) — behavior
|
|
10
|
+
* unchanged from Phase 1.
|
|
11
|
+
* - the new `primitive settings show|pull|push|diff` command
|
|
12
|
+
* (`cli/src/commands/settings.ts`) calls the higher-level orchestrators
|
|
13
|
+
* (`pullAppSettings`, `pushAppSettings`, `diffAppSettings`, `showAppSettings`).
|
|
14
|
+
*
|
|
15
|
+
* Both directions share the same `app.toml`, the same field descriptor
|
|
16
|
+
* (`cli/src/lib/app-settings-descriptor.ts`), and the same single
|
|
17
|
+
* `entities.app.contentHash` sync-state entry, so `settings push` then
|
|
18
|
+
* `sync push` (or the reverse) is idempotent — the second one skips on the
|
|
19
|
+
* unchanged hash.
|
|
20
|
+
*
|
|
21
|
+
* `googleClientSecret` never leaves the server through here: pull omits it,
|
|
22
|
+
* push errors on it (pointing at `primitive apps update --google-client-secret`),
|
|
23
|
+
* and `settings show` redacts it in both the rendered and `--json` views.
|
|
24
|
+
*/
|
|
25
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
26
|
+
import { join } from "path";
|
|
27
|
+
import { createHash } from "crypto";
|
|
28
|
+
import { parseConfigToml, stringifyConfigToml } from "../lib/config-toml.js";
|
|
29
|
+
import { APP_SETTINGS_DESCRIPTOR, APP_SETTINGS_SECTIONS, serializeAppSettingsToToml, parseTomlToAppSettings, } from "../lib/app-settings-descriptor.js";
|
|
30
|
+
import { getServerUrl } from "../lib/config.js";
|
|
31
|
+
import { success, error, info, warn, json, result as printResult, divider, } from "../lib/output.js";
|
|
32
|
+
/** The app-settings file name inside a sync directory. */
|
|
33
|
+
export const APP_TOML_FILENAME = "app.toml";
|
|
34
|
+
/** Absolute path to `app.toml` inside a sync directory. */
|
|
35
|
+
export function appTomlPath(configDir) {
|
|
36
|
+
return join(configDir, APP_TOML_FILENAME);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Serialize server settings into the `app.toml` string (pull direction).
|
|
40
|
+
* Descriptor-driven; `googleClientSecret` is never emitted. This is the single
|
|
41
|
+
* serializer both `sync pull` and `settings pull` use.
|
|
42
|
+
*/
|
|
43
|
+
export function serializeAppSettings(settings) {
|
|
44
|
+
return stringifyConfigToml(serializeAppSettingsToToml(settings));
|
|
45
|
+
}
|
|
46
|
+
/** SHA-256 of a file's bytes — the per-file content hash tracked in sync state. */
|
|
47
|
+
function contentHashOfFile(filePath) {
|
|
48
|
+
return createHash("sha256").update(readFileSync(filePath)).digest("hex");
|
|
49
|
+
}
|
|
50
|
+
function ensureDir(dirPath) {
|
|
51
|
+
if (!existsSync(dirPath))
|
|
52
|
+
mkdirSync(dirPath, { recursive: true });
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Write `app.toml` from server settings and return its content hash. Shared by
|
|
56
|
+
* `sync pull` and `settings pull` so the two produce byte-identical files and
|
|
57
|
+
* the same hash.
|
|
58
|
+
*/
|
|
59
|
+
export function writeAppSettingsToml(configDir, settings) {
|
|
60
|
+
const path = appTomlPath(configDir);
|
|
61
|
+
writeFileSync(path, serializeAppSettings(settings));
|
|
62
|
+
return contentHashOfFile(path);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Validate a parsed `app.toml` for push and return the fatal errors (a
|
|
66
|
+
* hand-added secret key, a type mismatch). An empty array means the push may
|
|
67
|
+
* proceed. Warnings (unrecognized keys) are intentionally not returned here —
|
|
68
|
+
* the caller surfaces those at apply time. Shared by the `sync push` preflight
|
|
69
|
+
* and `settings push`.
|
|
70
|
+
*/
|
|
71
|
+
export function collectAppSettingsPushErrors(tomlData, options = {}) {
|
|
72
|
+
return parseTomlToAppSettings(tomlData, options).errors;
|
|
73
|
+
}
|
|
74
|
+
// --- Shared single sync-state entry (entities.app) -------------------------
|
|
75
|
+
// `settings pull/push` read and write the SAME `.primitive-sync.json` that
|
|
76
|
+
// `sync` maintains, touching only `entities.app` and preserving every other
|
|
77
|
+
// entity. Kept as small local load/save helpers (rather than importing
|
|
78
|
+
// `sync.ts`) to avoid an import cycle — `sync.ts` imports the serializer above.
|
|
79
|
+
function syncStatePath(configDir) {
|
|
80
|
+
return join(configDir, ".primitive-sync.json");
|
|
81
|
+
}
|
|
82
|
+
function loadSyncState(configDir) {
|
|
83
|
+
const p = syncStatePath(configDir);
|
|
84
|
+
if (!existsSync(p))
|
|
85
|
+
return null;
|
|
86
|
+
try {
|
|
87
|
+
return JSON.parse(readFileSync(p, "utf-8"));
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function saveSyncState(configDir, state) {
|
|
94
|
+
writeFileSync(syncStatePath(configDir), JSON.stringify(state, null, 2));
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Update `entities.app.contentHash`, preserving all other entities.
|
|
98
|
+
*
|
|
99
|
+
* On a cross-app stamp (the loaded state belongs to a different app than the
|
|
100
|
+
* one we just pulled from / pushed to) this mirrors `sync push` (see
|
|
101
|
+
* `sync.ts`): it rebinds the sync state to the target app with fresh entities,
|
|
102
|
+
* then records the app-settings hash. Without the rebind the stored
|
|
103
|
+
* `state.appId` would stay pointing at the source app, so every later
|
|
104
|
+
* `settings push <target>` would keep computing `isCrossAppPush` as true — it
|
|
105
|
+
* would ignore the stored hash and keep stripping `[app].name`, making it
|
|
106
|
+
* impossible to rename the target app via `app.toml`.
|
|
107
|
+
*/
|
|
108
|
+
function stampAppContentHash(configDir, appId, contentHash) {
|
|
109
|
+
const now = new Date().toISOString();
|
|
110
|
+
const existing = loadSyncState(configDir);
|
|
111
|
+
const isCrossAppStamp = !!(existing && existing.appId !== appId);
|
|
112
|
+
const state = existing && !isCrossAppStamp
|
|
113
|
+
? existing
|
|
114
|
+
: {
|
|
115
|
+
appId,
|
|
116
|
+
serverUrl: existing?.serverUrl ?? getServerUrl(),
|
|
117
|
+
lastSyncedAt: now,
|
|
118
|
+
entities: {},
|
|
119
|
+
};
|
|
120
|
+
state.entities.app = { modifiedAt: now, contentHash };
|
|
121
|
+
saveSyncState(configDir, state);
|
|
122
|
+
}
|
|
123
|
+
// --- googleClientSecret redaction (settings show) --------------------------
|
|
124
|
+
/** Placeholder shown in `settings show` in place of any secret field value. */
|
|
125
|
+
export const REDACTED_PLACEHOLDER = "[redacted — set via: primitive apps update <appId> --google-client-secret]";
|
|
126
|
+
/**
|
|
127
|
+
* Return a copy of the server settings with every secret descriptor field
|
|
128
|
+
* (currently `googleClientSecret`) redacted when it holds a value. `null`/empty
|
|
129
|
+
* values are left untouched — there is no secret to hide. Used for BOTH the
|
|
130
|
+
* rendered and `--json` outputs of `settings show` so the real secret never
|
|
131
|
+
* leaves the server through this command (codex design-review concern #2).
|
|
132
|
+
*/
|
|
133
|
+
export function redactSecretFields(settings) {
|
|
134
|
+
const out = { ...settings };
|
|
135
|
+
for (const d of APP_SETTINGS_DESCRIPTOR) {
|
|
136
|
+
if (d.secret && out[d.field])
|
|
137
|
+
out[d.field] = REDACTED_PLACEHOLDER;
|
|
138
|
+
}
|
|
139
|
+
return out;
|
|
140
|
+
}
|
|
141
|
+
// --- Display helpers -------------------------------------------------------
|
|
142
|
+
function formatValue(value) {
|
|
143
|
+
if (value === undefined)
|
|
144
|
+
return "(not set)";
|
|
145
|
+
if (value === null)
|
|
146
|
+
return "(null)";
|
|
147
|
+
if (Array.isArray(value))
|
|
148
|
+
return value.length === 0 ? "[]" : `[${value.join(", ")}]`;
|
|
149
|
+
if (typeof value === "object")
|
|
150
|
+
return JSON.stringify(value);
|
|
151
|
+
return String(value);
|
|
152
|
+
}
|
|
153
|
+
/** Order-insensitive-free deep equality good enough for settings scalars/arrays. */
|
|
154
|
+
function settingsEqual(a, b) {
|
|
155
|
+
return JSON.stringify(a ?? null) === JSON.stringify(b ?? null);
|
|
156
|
+
}
|
|
157
|
+
// --- Command orchestrators (used by cli/src/commands/settings.ts) ----------
|
|
158
|
+
/**
|
|
159
|
+
* `settings show` — render the current server-effective settings grouped by
|
|
160
|
+
* `app.toml` section, with `googleClientSecret` redacted. `--json` emits the
|
|
161
|
+
* full (redacted) server response.
|
|
162
|
+
*/
|
|
163
|
+
export async function showAppSettings(client, appId, options = {}) {
|
|
164
|
+
try {
|
|
165
|
+
const settings = await client.getAppSettings(appId);
|
|
166
|
+
const redacted = redactSecretFields(settings ?? {});
|
|
167
|
+
if (options.json) {
|
|
168
|
+
json(redacted);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
for (const section of APP_SETTINGS_SECTIONS) {
|
|
172
|
+
const descriptors = APP_SETTINGS_DESCRIPTOR.filter((d) => d.section === section);
|
|
173
|
+
divider();
|
|
174
|
+
info(`[${section}]`);
|
|
175
|
+
for (const d of descriptors) {
|
|
176
|
+
printResult(` ${d.key}`, formatValue(redacted[d.field]));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
error(err.message);
|
|
182
|
+
process.exit(1);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* `settings pull` — fetch the server settings, write `app.toml`, and stamp the
|
|
187
|
+
* shared `entities.app.contentHash`. Same file and hash as `sync pull`.
|
|
188
|
+
*/
|
|
189
|
+
export async function pullAppSettings(client, appId, configDir, options = {}) {
|
|
190
|
+
try {
|
|
191
|
+
const settings = await client.getAppSettings(appId);
|
|
192
|
+
if (!settings) {
|
|
193
|
+
error(`No settings returned for app ${appId}.`);
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
ensureDir(configDir);
|
|
197
|
+
const contentHash = writeAppSettingsToml(configDir, settings);
|
|
198
|
+
stampAppContentHash(configDir, appId, contentHash);
|
|
199
|
+
if (options.json) {
|
|
200
|
+
json({ wrote: true, path: appTomlPath(configDir), contentHash });
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
success(`Wrote ${appTomlPath(configDir)}`);
|
|
204
|
+
}
|
|
205
|
+
catch (err) {
|
|
206
|
+
error(err.message);
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* `settings push` — read `app.toml`, validate (abort before any PUT on a secret
|
|
212
|
+
* key or a type mismatch), skip when unchanged since the last sync unless
|
|
213
|
+
* `--force`, then apply via `PUT /settings` and re-stamp the shared content
|
|
214
|
+
* hash. Cross-app pushes (state's app differs from the target) always apply and
|
|
215
|
+
* strip `name`, matching `sync push`.
|
|
216
|
+
*/
|
|
217
|
+
export async function pushAppSettings(client, appId, configDir, options = {}) {
|
|
218
|
+
try {
|
|
219
|
+
const path = appTomlPath(configDir);
|
|
220
|
+
if (!existsSync(path)) {
|
|
221
|
+
error(`No ${APP_TOML_FILENAME} found at ${path}. Run 'primitive settings pull' first.`);
|
|
222
|
+
process.exit(1);
|
|
223
|
+
}
|
|
224
|
+
const state = loadSyncState(configDir);
|
|
225
|
+
const isCrossAppPush = !!(state && state.appId !== appId);
|
|
226
|
+
let tomlData;
|
|
227
|
+
try {
|
|
228
|
+
tomlData = parseConfigToml(readFileSync(path, "utf-8"));
|
|
229
|
+
}
|
|
230
|
+
catch (err) {
|
|
231
|
+
error(`Aborting push: could not parse ${APP_TOML_FILENAME}: ${err?.message || String(err)}`);
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
const { settings, warnings, errors } = parseTomlToAppSettings(tomlData, {
|
|
235
|
+
isCrossAppPush,
|
|
236
|
+
});
|
|
237
|
+
// Fail before any mutation on a secret key or a type mismatch.
|
|
238
|
+
if (errors.length > 0) {
|
|
239
|
+
error(`Aborting push: ${errors.length} validation error(s) in ${APP_TOML_FILENAME} — no changes were applied.`);
|
|
240
|
+
for (const e of errors)
|
|
241
|
+
error(` ${e}`);
|
|
242
|
+
process.exit(1);
|
|
243
|
+
}
|
|
244
|
+
// Skip when nothing changed since the last sync (shared content hash).
|
|
245
|
+
const storedHash = isCrossAppPush
|
|
246
|
+
? undefined
|
|
247
|
+
: state?.entities?.app?.contentHash;
|
|
248
|
+
const changed = options.force || !storedHash || contentHashOfFile(path) !== storedHash;
|
|
249
|
+
if (!changed) {
|
|
250
|
+
if (options.json) {
|
|
251
|
+
json({ applied: false, skipped: true, reason: "unchanged" });
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
info("Skipped app settings (unchanged). Use --force to push anyway.");
|
|
255
|
+
}
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
for (const w of warnings)
|
|
259
|
+
warn(` ${w}`);
|
|
260
|
+
if (options.dryRun) {
|
|
261
|
+
if (options.json) {
|
|
262
|
+
json({ applied: false, dryRun: true, settings });
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
info("[dry-run] Would update app settings.");
|
|
266
|
+
}
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
await client.updateAppSettings(appId, settings);
|
|
270
|
+
stampAppContentHash(configDir, appId, contentHashOfFile(path));
|
|
271
|
+
if (options.json) {
|
|
272
|
+
json({ applied: true, fields: Object.keys(settings) });
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
success("Updated app settings.");
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
error(err.message);
|
|
279
|
+
process.exit(1);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* `settings diff` — report per-field differences between the local `app.toml`
|
|
284
|
+
* push payload and the current server settings. Only keys present in the TOML
|
|
285
|
+
* are compared, so a server value that equals a descriptor default (and is
|
|
286
|
+
* therefore omitted from `app.toml`) is never flagged as a spurious difference.
|
|
287
|
+
*/
|
|
288
|
+
export async function diffAppSettings(client, appId, configDir, options = {}) {
|
|
289
|
+
try {
|
|
290
|
+
const path = appTomlPath(configDir);
|
|
291
|
+
if (!existsSync(path)) {
|
|
292
|
+
error(`No ${APP_TOML_FILENAME} found at ${path}. Run 'primitive settings pull' first.`);
|
|
293
|
+
process.exit(1);
|
|
294
|
+
}
|
|
295
|
+
const remote = (await client.getAppSettings(appId)) ?? {};
|
|
296
|
+
const tomlData = parseConfigToml(readFileSync(path, "utf-8"));
|
|
297
|
+
// Present-only push payload — omitted keys are absent, so they can't be
|
|
298
|
+
// flagged against a server default.
|
|
299
|
+
const { settings: local } = parseTomlToAppSettings(tomlData, {});
|
|
300
|
+
const diffs = [];
|
|
301
|
+
for (const d of APP_SETTINGS_DESCRIPTOR) {
|
|
302
|
+
if (d.secret)
|
|
303
|
+
continue;
|
|
304
|
+
if (!(d.field in local))
|
|
305
|
+
continue;
|
|
306
|
+
const localVal = local[d.field];
|
|
307
|
+
const remoteVal = remote[d.field];
|
|
308
|
+
if (!settingsEqual(localVal, remoteVal)) {
|
|
309
|
+
diffs.push({
|
|
310
|
+
field: d.field,
|
|
311
|
+
section: d.section,
|
|
312
|
+
key: d.key,
|
|
313
|
+
local: localVal,
|
|
314
|
+
remote: remoteVal,
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (options.json) {
|
|
319
|
+
json({ diffs });
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
if (diffs.length === 0) {
|
|
323
|
+
success(`No differences — ${APP_TOML_FILENAME} matches server settings.`);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
info(`${diffs.length} field(s) differ between ${APP_TOML_FILENAME} and the server:`);
|
|
327
|
+
for (const df of diffs) {
|
|
328
|
+
divider();
|
|
329
|
+
info(`[${df.section}].${df.key}`);
|
|
330
|
+
printResult(" local", formatValue(df.local));
|
|
331
|
+
printResult(" remote", formatValue(df.remote));
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
catch (err) {
|
|
335
|
+
error(err.message);
|
|
336
|
+
process.exit(1);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
//# sourceMappingURL=sync-app-settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-app-settings.js","sourceRoot":"","sources":["../../../src/commands/sync-app-settings.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import { ApiClient } from "../lib/api-client.js";
|
|
3
|
+
import { type PresenceOutcome } from "../lib/sync-resource-types.js";
|
|
3
4
|
/**
|
|
4
5
|
* Wrap a server-side error so the printed message identifies which entity
|
|
5
6
|
* was in flight. Used by every entity create/update/delete call site in the
|
|
@@ -66,32 +67,28 @@ export declare function hashWorkflowTomlForDiff(parsed: any): string;
|
|
|
66
67
|
* through `hashWorkflowTomlForDiff` so it lines up with the local-file hash.
|
|
67
68
|
*/
|
|
68
69
|
export declare function hashRemoteWorkflowForDiff(workflow: any, draft: any, configs: any[]): string;
|
|
70
|
+
export interface ParsedAuthSettings {
|
|
71
|
+
settings: Record<string, any>;
|
|
72
|
+
warnings: string[];
|
|
73
|
+
}
|
|
69
74
|
/**
|
|
70
75
|
* Build the [auth] block of app.toml from server settings (pull direction).
|
|
71
76
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* an empty list on pull is not lossy.
|
|
77
|
+
* Thin wrapper over the shared field descriptor
|
|
78
|
+
* (`cli/src/lib/app-settings-descriptor.ts`), which now owns the [auth] field
|
|
79
|
+
* set that `AUTH_BOOLEAN_KEYS`/`RECOGNIZED_AUTH_KEYS` used to hard-code. The
|
|
80
|
+
* descriptor drives all four sections in one place, so pull, push, and the
|
|
81
|
+
* unrecognized-key warning can never drift apart. `googleClientSecret` is a
|
|
82
|
+
* secret descriptor entry and is never written.
|
|
79
83
|
*/
|
|
80
84
|
export declare function serializeAuthBlock(settings: any): Record<string, any>;
|
|
81
|
-
export interface ParsedAuthSettings {
|
|
82
|
-
settings: Record<string, any>;
|
|
83
|
-
warnings: string[];
|
|
84
|
-
}
|
|
85
85
|
/**
|
|
86
86
|
* Translate the [auth] block of app.toml into app-settings fields (push
|
|
87
|
-
* direction).
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* `appleAudiences = []` is forwarded too; the server normalizes [] -> null
|
|
93
|
-
* ("no audiences"). Keys outside RECOGNIZED_AUTH_KEYS produce a warning rather
|
|
94
|
-
* than a hard error, so a typo or a future key doesn't silently drop.
|
|
87
|
+
* direction). Kept as a focused helper over the shared descriptor; the full
|
|
88
|
+
* push path uses `parseTomlToAppSettings` for every section. Only keys present
|
|
89
|
+
* in the TOML are forwarded, so an omitted key never overwrites server state.
|
|
90
|
+
* Descriptor errors (a secret key, a type mismatch) are surfaced alongside the
|
|
91
|
+
* unrecognized-key warnings.
|
|
95
92
|
*/
|
|
96
93
|
export declare function parseAppAuthSettings(auth: Record<string, any>): ParsedAuthSettings;
|
|
97
94
|
type VarEntity = {
|
|
@@ -320,6 +317,24 @@ export declare function pullScripts(client: ApiClient, appId: string, configDir:
|
|
|
320
317
|
contentHash?: string;
|
|
321
318
|
}>;
|
|
322
319
|
count: number;
|
|
320
|
+
/**
|
|
321
|
+
* Which scripts the server listed, for the #1659 prune pass. `ok: false` when
|
|
322
|
+
* the listing failed (an older server without the route, or a transient
|
|
323
|
+
* error) or when any per-script fetch failed — in either case this pull's
|
|
324
|
+
* picture of the type is incomplete and must not drive deletions. Scripts
|
|
325
|
+
* skipped for having no active config are still *present*, so their keys stay
|
|
326
|
+
* in the set and their local `.rhai` survives.
|
|
327
|
+
*/
|
|
328
|
+
presence: PresenceOutcome;
|
|
329
|
+
/**
|
|
330
|
+
* Whether the script LISTING succeeded. Distinct from `presence`: a failed
|
|
331
|
+
* per-script fetch blocks pruning but still leaves the other scripts written,
|
|
332
|
+
* so their fresh state entries must be kept. Only a failed listing means
|
|
333
|
+
* nothing was written and the prior state slot should be preserved whole.
|
|
334
|
+
*/
|
|
335
|
+
listOk: boolean;
|
|
336
|
+
/** Names the server listed, empty when the listing failed. */
|
|
337
|
+
serverKeys: string[];
|
|
323
338
|
}>;
|
|
324
339
|
export declare function registerSyncCommands(program: Command): void;
|
|
325
340
|
export {};
|