primitive-admin 1.1.0-alpha.73 → 1.1.0-alpha.74

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.
Files changed (94) hide show
  1. package/README.md +18 -25
  2. package/assets/skill/skills/primitive-platform/SKILL.md +30 -14
  3. package/dist/bin/primitive.js +14 -11
  4. package/dist/bin/primitive.js.map +1 -1
  5. package/dist/src/commands/analytics.js +117 -2
  6. package/dist/src/commands/analytics.js.map +1 -1
  7. package/dist/src/commands/auth.js +13 -107
  8. package/dist/src/commands/auth.js.map +1 -1
  9. package/dist/src/commands/collection-type-configs.js +1 -1
  10. package/dist/src/commands/collection-type-configs.js.map +1 -1
  11. package/dist/src/commands/database-type-configs.js +1 -1
  12. package/dist/src/commands/database-type-configs.js.map +1 -1
  13. package/dist/src/commands/databases.js +1 -1
  14. package/dist/src/commands/databases.js.map +1 -1
  15. package/dist/src/commands/documents.js +749 -29
  16. package/dist/src/commands/documents.js.map +1 -1
  17. package/dist/src/commands/env.js +44 -6
  18. package/dist/src/commands/env.js.map +1 -1
  19. package/dist/src/commands/functions.d.ts +20 -0
  20. package/dist/src/commands/functions.js +329 -0
  21. package/dist/src/commands/functions.js.map +1 -0
  22. package/dist/src/commands/groups.js +1 -1
  23. package/dist/src/commands/groups.js.map +1 -1
  24. package/dist/src/commands/init.js +2 -15
  25. package/dist/src/commands/init.js.map +1 -1
  26. package/dist/src/commands/integrations.js +5 -3
  27. package/dist/src/commands/integrations.js.map +1 -1
  28. package/dist/src/commands/prompts.js +5 -7
  29. package/dist/src/commands/prompts.js.map +1 -1
  30. package/dist/src/commands/rule-sets.js +1 -1
  31. package/dist/src/commands/rule-sets.js.map +1 -1
  32. package/dist/src/commands/scripts.js +6 -7
  33. package/dist/src/commands/scripts.js.map +1 -1
  34. package/dist/src/commands/sync.d.ts +63 -0
  35. package/dist/src/commands/sync.js +650 -2
  36. package/dist/src/commands/sync.js.map +1 -1
  37. package/dist/src/commands/workflows.js +5 -7
  38. package/dist/src/commands/workflows.js.map +1 -1
  39. package/dist/src/lib/api-client.d.ts +156 -1
  40. package/dist/src/lib/api-client.js +219 -3
  41. package/dist/src/lib/api-client.js.map +1 -1
  42. package/dist/src/lib/app-settings-descriptor.js +4 -0
  43. package/dist/src/lib/app-settings-descriptor.js.map +1 -1
  44. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js +5 -7
  45. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js.map +1 -1
  46. package/dist/src/lib/config-object-descriptor.js +39 -0
  47. package/dist/src/lib/config-object-descriptor.js.map +1 -1
  48. package/dist/src/lib/config-surface.d.ts +10 -0
  49. package/dist/src/lib/config-surface.js +17 -0
  50. package/dist/src/lib/config-surface.js.map +1 -1
  51. package/dist/src/lib/config.d.ts +13 -2
  52. package/dist/src/lib/config.js +20 -37
  53. package/dist/src/lib/config.js.map +1 -1
  54. package/dist/src/lib/credentials-store.d.ts +4 -12
  55. package/dist/src/lib/credentials-store.js +49 -82
  56. package/dist/src/lib/credentials-store.js.map +1 -1
  57. package/dist/src/lib/env-resolver-core.d.ts +23 -7
  58. package/dist/src/lib/env-resolver-core.js +44 -4
  59. package/dist/src/lib/env-resolver-core.js.map +1 -1
  60. package/dist/src/lib/function-bundle.d.ts +131 -0
  61. package/dist/src/lib/function-bundle.js +321 -0
  62. package/dist/src/lib/function-bundle.js.map +1 -0
  63. package/dist/src/lib/function-sync.d.ts +157 -0
  64. package/dist/src/lib/function-sync.js +371 -0
  65. package/dist/src/lib/function-sync.js.map +1 -0
  66. package/dist/src/lib/function-triggers.d.ts +54 -0
  67. package/dist/src/lib/function-triggers.js +223 -0
  68. package/dist/src/lib/function-triggers.js.map +1 -0
  69. package/dist/src/lib/generated-config-surfaces.d.ts +1 -0
  70. package/dist/src/lib/generated-config-surfaces.js +279 -1
  71. package/dist/src/lib/generated-config-surfaces.js.map +1 -1
  72. package/dist/src/lib/init-ios-links.d.ts +6 -5
  73. package/dist/src/lib/init-ios-links.js +8 -7
  74. package/dist/src/lib/init-ios-links.js.map +1 -1
  75. package/dist/src/lib/init-xcode.d.ts +4 -3
  76. package/dist/src/lib/init-xcode.js +28 -5
  77. package/dist/src/lib/init-xcode.js.map +1 -1
  78. package/dist/src/lib/ios-app-id.d.ts +34 -0
  79. package/dist/src/lib/ios-app-id.js +69 -0
  80. package/dist/src/lib/ios-app-id.js.map +1 -0
  81. package/dist/src/lib/project-config.d.ts +15 -1
  82. package/dist/src/lib/project-config.js +31 -3
  83. package/dist/src/lib/project-config.js.map +1 -1
  84. package/dist/src/lib/sync-resource-types.d.ts +21 -2
  85. package/dist/src/lib/sync-resource-types.js +104 -6
  86. package/dist/src/lib/sync-resource-types.js.map +1 -1
  87. package/dist/src/lib/test-case-variables.d.ts +14 -0
  88. package/dist/src/lib/test-case-variables.js +42 -0
  89. package/dist/src/lib/test-case-variables.js.map +1 -1
  90. package/dist/src/lib/workflow-usage.d.ts +198 -0
  91. package/dist/src/lib/workflow-usage.js +312 -0
  92. package/dist/src/lib/workflow-usage.js.map +1 -0
  93. package/dist/src/types/index.d.ts +12 -2
  94. package/package.json +2 -1
@@ -0,0 +1,198 @@
1
+ /**
2
+ * `primitive analytics workflow-usage` — the value-in / value-out half
3
+ * (#3130, criteria 2 and 3 of `projects/workflow-usage/intent.md`).
4
+ *
5
+ * The per-app report is the server's (#3132,
6
+ * `GET /admin/api/apps/{appId}/workflows/usage`). What lives here is
7
+ * everything the CLI decides for itself: the `--window-days` mirror, the
8
+ * cross-app merge the intent puts on the client rather than in a cross-tenant
9
+ * endpoint, and the table layout. Keeping it pure means the merge — the part
10
+ * a live test can only observe through a whole shared table — is provable
11
+ * exactly, with no server and no doubles.
12
+ */
13
+ export declare const USAGE_CLI_MIN_WINDOW_DAYS = 1;
14
+ export declare const USAGE_CLI_MAX_WINDOW_DAYS = 45;
15
+ export declare const USAGE_CLI_DEFAULT_WINDOW_DAYS = 30;
16
+ /** The one `--window-days` rejection: names the range and the default. */
17
+ export declare const WINDOW_DAYS_FLAG_ERROR: string;
18
+ /** `--all-apps` answers a different question than one app's report. */
19
+ export declare const ALL_APPS_CONFLICT_ERROR: string;
20
+ /**
21
+ * The role gate's refusal.
22
+ *
23
+ * `GET /admin/api/apps` has no role filter and the per-app usage endpoint
24
+ * admits any admin assigned to the app, so an app admin who happens to be
25
+ * assigned to every app would otherwise receive the aggregate. The gate is a
26
+ * role check, not a hoped-for 403 (D3130-002).
27
+ */
28
+ export declare const ALL_APPS_SUPER_ADMIN_ERROR = "--all-apps is super-admin only. Run it without --all-apps for one app's report.";
29
+ export interface UsageWorkflowRef {
30
+ workflowId: string;
31
+ workflowKey: string;
32
+ }
33
+ export interface UsageKindRow {
34
+ kind: string;
35
+ workflows: number;
36
+ runs: number;
37
+ }
38
+ export interface UsageErrorEntry extends UsageWorkflowRef {
39
+ resource: "config" | "runs";
40
+ message: string;
41
+ }
42
+ /** The frozen response body of `GET .../workflows/usage` (#3132). */
43
+ export interface WorkflowUsageReport {
44
+ windowDays: number;
45
+ workflowCount: number;
46
+ runsInWindow: number;
47
+ items: UsageKindRow[];
48
+ syncCallable: UsageWorkflowRef[];
49
+ idleWorkflows: UsageWorkflowRef[];
50
+ truncated: UsageWorkflowRef[];
51
+ errors: UsageErrorEntry[];
52
+ complete: boolean;
53
+ }
54
+ /** A workflow reference in the merge: the same ref, plus its app. */
55
+ export interface MergedWorkflowRef extends UsageWorkflowRef {
56
+ appId: string;
57
+ }
58
+ /** A merged kind row: `apps` is the number of apps that configure the kind. */
59
+ export interface MergedKindRow {
60
+ kind: string;
61
+ workflows: number;
62
+ apps: number;
63
+ runs: number;
64
+ }
65
+ /**
66
+ * A merged error. `resource: "app"` is the CLI's own: the app was listed but
67
+ * its report could not be read, so the merge is answering over fewer apps
68
+ * than it counted and says so.
69
+ */
70
+ export interface MergedErrorEntry {
71
+ appId: string;
72
+ workflowId?: string;
73
+ workflowKey?: string;
74
+ resource: "config" | "runs" | "app";
75
+ message: string;
76
+ }
77
+ /** The merged shape, frozen for #3131. */
78
+ export interface MergedUsageReport {
79
+ windowDays: number;
80
+ apps: number;
81
+ workflowCount: number;
82
+ runsInWindow: number;
83
+ items: MergedKindRow[];
84
+ syncCallable: MergedWorkflowRef[];
85
+ idleWorkflows: MergedWorkflowRef[];
86
+ truncated: MergedWorkflowRef[];
87
+ errors: MergedErrorEntry[];
88
+ complete: boolean;
89
+ }
90
+ /** One app's outcome: its report, or why the CLI could not read it. */
91
+ export type PerAppUsageResult = {
92
+ appId: string;
93
+ report: WorkflowUsageReport;
94
+ } | {
95
+ appId: string;
96
+ error: string;
97
+ };
98
+ export type WindowDaysFlag = {
99
+ omitted: true;
100
+ effective: number;
101
+ } | {
102
+ omitted: false;
103
+ effective: number;
104
+ } | {
105
+ error: string;
106
+ };
107
+ /**
108
+ * Validate the raw `--window-days` string against the frozen contract.
109
+ *
110
+ * Deliberately NOT `parseInt`, which the analytics siblings use: `parseInt`
111
+ * turns `1.5` into `1` and `46abc` into `46`, so the server's strict `/^\d+$/`
112
+ * check would never see what the user typed. `omitted` tells the caller to
113
+ * leave the query parameter off entirely (the server applies its own default)
114
+ * while still giving the merge a well-defined window to report.
115
+ */
116
+ export declare function parseWindowDaysFlag(raw: string | undefined): WindowDaysFlag;
117
+ /**
118
+ * The same two spellings the server accepts (`admin-api.ts`).
119
+ *
120
+ * Deliberately the lenient pair rather than the canonical `super-admin`-only
121
+ * rule: the data this command reads is gated server-side by
122
+ * `requireAppAccess`, which treats BOTH spellings as super-admin, so a legacy
123
+ * `superadmin` account can already read every app's report one app at a time.
124
+ * A stricter client-side gate would refuse a merge of exactly the reports the
125
+ * server hands that account anyway — a false refusal, not a boundary. The gate
126
+ * exists to make the APP-ADMIN refusal deterministic (D3130-002); enforcement
127
+ * stays where it is.
128
+ */
129
+ export declare function isSuperAdminRole(role: string | null | undefined): boolean;
130
+ /**
131
+ * How many times `--all-apps` drains the global apps list before merging.
132
+ *
133
+ * `GET /admin/api/apps` paginates by re-scanning `App.iterateAll()` from the
134
+ * start of each page, so a table that changes while it is walked both repeats
135
+ * and DROPS rows. Measured against the dev table with three apps seeded and
136
+ * left untouched: 2 of 10 single drains missed one of them, while the union of
137
+ * two consecutive drains missed none in 9 of 9 samples and three in 8 of 8.
138
+ * One drain is therefore not a sound basis for a report that claims to cover
139
+ * every app.
140
+ */
141
+ export declare const GLOBAL_APPS_MAX_DRAINS = 3;
142
+ /** An app as the global list identifies it. */
143
+ export interface GlobalAppRef {
144
+ appId: string;
145
+ name: string;
146
+ }
147
+ /**
148
+ * Drain the apps list until it converges, and return the union.
149
+ *
150
+ * The union is what makes a dropped app unlikely: each drain independently
151
+ * loses a different row, so an app has to be missed by every drain to be
152
+ * missed by the merge. Draining stops as soon as a drain after the first adds
153
+ * nothing new — the enumeration agreed with itself — and otherwise at
154
+ * `maxDrains`, because on a table where apps are continuously created there is
155
+ * no fixed point to wait for and a report is more useful than a hang.
156
+ *
157
+ * Left deliberately independent of the merge's `complete` flag: `complete`
158
+ * answers "was every app's report readable", and no client-side walk of this
159
+ * route can promise more than the union above.
160
+ */
161
+ export declare function drainAppsUntilConverged(drain: () => Promise<GlobalAppRef[]>, maxDrains?: number): Promise<GlobalAppRef[]>;
162
+ /**
163
+ * Whether a per-app failure ends the walk.
164
+ *
165
+ * A 400, 401 or 403 says the caller cannot ask this question — of this app
166
+ * today, of any app tomorrow — so continuing would print a merged report over
167
+ * a silently chosen subset, which answers a different question. Anything else
168
+ * (5xx, a network blip) is recorded as an `app` error and the walk continues.
169
+ */
170
+ export declare function isAbortStatus(status: number | undefined | null): boolean;
171
+ /**
172
+ * Merge one report per app into the cross-app answer.
173
+ *
174
+ * `windowDays` is the caller's effective window, not any report's, so the
175
+ * merge is well-defined over zero apps. `apps` is the number of apps LISTED,
176
+ * including any whose report failed — a count that shrank silently would
177
+ * misreport the scope of the answer.
178
+ */
179
+ export declare function mergeUsageReports(windowDays: number, results: PerAppUsageResult[]): MergedUsageReport;
180
+ /**
181
+ * One printed block. `heading` goes to stderr (the CLI's `heading()`), `body`
182
+ * to stdout, so a table-mode run still pipes its data cleanly.
183
+ */
184
+ export interface UsageOutputBlock {
185
+ heading?: string;
186
+ body: string;
187
+ }
188
+ /**
189
+ * The single-app table: the audit script's sections, in the script's order,
190
+ * in the CLI's `formatTable` idiom.
191
+ */
192
+ export declare function renderUsageReport(report: WorkflowUsageReport): UsageOutputBlock[];
193
+ /** The merged table: the same sections, with an APPS column and `appId/` refs. */
194
+ export declare function renderMergedUsageReport(report: MergedUsageReport): UsageOutputBlock[];
195
+ /** An incomplete report is still printed — and still fails (intent). */
196
+ export declare function usageExitCode(report: {
197
+ complete: boolean;
198
+ }): number;
@@ -0,0 +1,312 @@
1
+ /**
2
+ * `primitive analytics workflow-usage` — the value-in / value-out half
3
+ * (#3130, criteria 2 and 3 of `projects/workflow-usage/intent.md`).
4
+ *
5
+ * The per-app report is the server's (#3132,
6
+ * `GET /admin/api/apps/{appId}/workflows/usage`). What lives here is
7
+ * everything the CLI decides for itself: the `--window-days` mirror, the
8
+ * cross-app merge the intent puts on the client rather than in a cross-tenant
9
+ * endpoint, and the table layout. Keeping it pure means the merge — the part
10
+ * a live test can only observe through a whole shared table — is provable
11
+ * exactly, with no server and no doubles.
12
+ */
13
+ import { formatTable } from "./output.js";
14
+ // ── The window contract ──────────────────────────────────────────────
15
+ //
16
+ // Mirrored from `src/workflows/usage-report.ts`, not imported: the CLI is a
17
+ // separately published package and does not depend on the worker's sources.
18
+ // The range is frozen by the intent's window-days decision (45 is the
19
+ // `WorkflowRun` retention), so the mirror cannot drift out from under the
20
+ // server. It exists because an `--all-apps` merge over zero apps has no
21
+ // request to carry the server's validation or its default.
22
+ export const USAGE_CLI_MIN_WINDOW_DAYS = 1;
23
+ export const USAGE_CLI_MAX_WINDOW_DAYS = 45;
24
+ export const USAGE_CLI_DEFAULT_WINDOW_DAYS = 30;
25
+ /** The one `--window-days` rejection: names the range and the default. */
26
+ export const WINDOW_DAYS_FLAG_ERROR = `--window-days must be an integer between ${USAGE_CLI_MIN_WINDOW_DAYS} and ` +
27
+ `${USAGE_CLI_MAX_WINDOW_DAYS} (workflow runs are retained for ` +
28
+ `${USAGE_CLI_MAX_WINDOW_DAYS} days); omit it for the default of ` +
29
+ `${USAGE_CLI_DEFAULT_WINDOW_DAYS}.`;
30
+ /** `--all-apps` answers a different question than one app's report. */
31
+ export const ALL_APPS_CONFLICT_ERROR = "--all-apps merges every app, so it cannot be combined with an app argument " +
32
+ "or --app. Drop one of them.";
33
+ /**
34
+ * The role gate's refusal.
35
+ *
36
+ * `GET /admin/api/apps` has no role filter and the per-app usage endpoint
37
+ * admits any admin assigned to the app, so an app admin who happens to be
38
+ * assigned to every app would otherwise receive the aggregate. The gate is a
39
+ * role check, not a hoped-for 403 (D3130-002).
40
+ */
41
+ export const ALL_APPS_SUPER_ADMIN_ERROR = "--all-apps is super-admin only. Run it without --all-apps for one app's report.";
42
+ /**
43
+ * Validate the raw `--window-days` string against the frozen contract.
44
+ *
45
+ * Deliberately NOT `parseInt`, which the analytics siblings use: `parseInt`
46
+ * turns `1.5` into `1` and `46abc` into `46`, so the server's strict `/^\d+$/`
47
+ * check would never see what the user typed. `omitted` tells the caller to
48
+ * leave the query parameter off entirely (the server applies its own default)
49
+ * while still giving the merge a well-defined window to report.
50
+ */
51
+ export function parseWindowDaysFlag(raw) {
52
+ if (raw === undefined) {
53
+ return { omitted: true, effective: USAGE_CLI_DEFAULT_WINDOW_DAYS };
54
+ }
55
+ if (!/^\d+$/.test(raw))
56
+ return { error: WINDOW_DAYS_FLAG_ERROR };
57
+ const value = Number.parseInt(raw, 10);
58
+ if (value < USAGE_CLI_MIN_WINDOW_DAYS || value > USAGE_CLI_MAX_WINDOW_DAYS) {
59
+ return { error: WINDOW_DAYS_FLAG_ERROR };
60
+ }
61
+ return { omitted: false, effective: value };
62
+ }
63
+ // ── The walk ─────────────────────────────────────────────────────────
64
+ /**
65
+ * The same two spellings the server accepts (`admin-api.ts`).
66
+ *
67
+ * Deliberately the lenient pair rather than the canonical `super-admin`-only
68
+ * rule: the data this command reads is gated server-side by
69
+ * `requireAppAccess`, which treats BOTH spellings as super-admin, so a legacy
70
+ * `superadmin` account can already read every app's report one app at a time.
71
+ * A stricter client-side gate would refuse a merge of exactly the reports the
72
+ * server hands that account anyway — a false refusal, not a boundary. The gate
73
+ * exists to make the APP-ADMIN refusal deterministic (D3130-002); enforcement
74
+ * stays where it is.
75
+ */
76
+ export function isSuperAdminRole(role) {
77
+ return role === "super-admin" || role === "superadmin";
78
+ }
79
+ /**
80
+ * How many times `--all-apps` drains the global apps list before merging.
81
+ *
82
+ * `GET /admin/api/apps` paginates by re-scanning `App.iterateAll()` from the
83
+ * start of each page, so a table that changes while it is walked both repeats
84
+ * and DROPS rows. Measured against the dev table with three apps seeded and
85
+ * left untouched: 2 of 10 single drains missed one of them, while the union of
86
+ * two consecutive drains missed none in 9 of 9 samples and three in 8 of 8.
87
+ * One drain is therefore not a sound basis for a report that claims to cover
88
+ * every app.
89
+ */
90
+ export const GLOBAL_APPS_MAX_DRAINS = 3;
91
+ /**
92
+ * Drain the apps list until it converges, and return the union.
93
+ *
94
+ * The union is what makes a dropped app unlikely: each drain independently
95
+ * loses a different row, so an app has to be missed by every drain to be
96
+ * missed by the merge. Draining stops as soon as a drain after the first adds
97
+ * nothing new — the enumeration agreed with itself — and otherwise at
98
+ * `maxDrains`, because on a table where apps are continuously created there is
99
+ * no fixed point to wait for and a report is more useful than a hang.
100
+ *
101
+ * Left deliberately independent of the merge's `complete` flag: `complete`
102
+ * answers "was every app's report readable", and no client-side walk of this
103
+ * route can promise more than the union above.
104
+ */
105
+ export async function drainAppsUntilConverged(drain, maxDrains = GLOBAL_APPS_MAX_DRAINS) {
106
+ const union = new Map();
107
+ for (let attempt = 0; attempt < Math.max(1, maxDrains); attempt++) {
108
+ const before = union.size;
109
+ for (const app of await drain()) {
110
+ // Deduplicate by appId: one drain hands the same app back on two pages
111
+ // whenever the list shifts under the cursor (5-15% of rows, measured),
112
+ // and a merged report that counted an app twice would report runs
113
+ // nobody started.
114
+ if (!app.appId || union.has(app.appId))
115
+ continue;
116
+ union.set(app.appId, app);
117
+ }
118
+ if (attempt > 0 && union.size === before)
119
+ break;
120
+ }
121
+ return [...union.values()];
122
+ }
123
+ /**
124
+ * Whether a per-app failure ends the walk.
125
+ *
126
+ * A 400, 401 or 403 says the caller cannot ask this question — of this app
127
+ * today, of any app tomorrow — so continuing would print a merged report over
128
+ * a silently chosen subset, which answers a different question. Anything else
129
+ * (5xx, a network blip) is recorded as an `app` error and the walk continues.
130
+ */
131
+ export function isAbortStatus(status) {
132
+ return status === 400 || status === 401 || status === 403;
133
+ }
134
+ // ── The merge ────────────────────────────────────────────────────────
135
+ function byAppThenKey(a, b) {
136
+ if (a.appId !== b.appId)
137
+ return a.appId < b.appId ? -1 : 1;
138
+ return a.workflowKey < b.workflowKey ? -1 : a.workflowKey > b.workflowKey ? 1 : 0;
139
+ }
140
+ function withApp(appId, refs) {
141
+ return (refs || []).map((ref) => ({
142
+ appId,
143
+ workflowId: ref.workflowId,
144
+ workflowKey: ref.workflowKey,
145
+ }));
146
+ }
147
+ /**
148
+ * Merge one report per app into the cross-app answer.
149
+ *
150
+ * `windowDays` is the caller's effective window, not any report's, so the
151
+ * merge is well-defined over zero apps. `apps` is the number of apps LISTED,
152
+ * including any whose report failed — a count that shrank silently would
153
+ * misreport the scope of the answer.
154
+ */
155
+ export function mergeUsageReports(windowDays, results) {
156
+ const perKind = new Map();
157
+ const syncCallable = [];
158
+ const idleWorkflows = [];
159
+ const truncated = [];
160
+ const errors = [];
161
+ let workflowCount = 0;
162
+ let runsInWindow = 0;
163
+ let complete = true;
164
+ for (const result of results) {
165
+ if ("error" in result) {
166
+ errors.push({
167
+ appId: result.appId,
168
+ resource: "app",
169
+ message: result.error,
170
+ });
171
+ complete = false;
172
+ continue;
173
+ }
174
+ const { appId, report } = result;
175
+ workflowCount += report.workflowCount || 0;
176
+ runsInWindow += report.runsInWindow || 0;
177
+ if (report.complete === false)
178
+ complete = false;
179
+ for (const row of report.items || []) {
180
+ const merged = perKind.get(row.kind) || {
181
+ workflows: 0,
182
+ runs: 0,
183
+ apps: new Set(),
184
+ };
185
+ merged.workflows += row.workflows;
186
+ merged.runs += row.runs;
187
+ merged.apps.add(appId);
188
+ perKind.set(row.kind, merged);
189
+ }
190
+ syncCallable.push(...withApp(appId, report.syncCallable));
191
+ idleWorkflows.push(...withApp(appId, report.idleWorkflows));
192
+ truncated.push(...withApp(appId, report.truncated));
193
+ for (const entry of report.errors || []) {
194
+ errors.push({
195
+ appId,
196
+ workflowId: entry.workflowId,
197
+ workflowKey: entry.workflowKey,
198
+ resource: entry.resource,
199
+ message: entry.message,
200
+ });
201
+ }
202
+ }
203
+ const items = [...perKind.entries()]
204
+ .map(([kind, row]) => ({
205
+ kind,
206
+ workflows: row.workflows,
207
+ apps: row.apps.size,
208
+ runs: row.runs,
209
+ }))
210
+ // The endpoint's comparator, and the audit script's: runs desc, then
211
+ // workflows desc, then `localeCompare` asc.
212
+ .sort((a, b) => b.runs - a.runs ||
213
+ b.workflows - a.workflows ||
214
+ a.kind.localeCompare(b.kind));
215
+ errors.sort((a, b) => (a.appId < b.appId ? -1 : a.appId > b.appId ? 1 : 0) ||
216
+ ((a.workflowKey ?? "") < (b.workflowKey ?? "")
217
+ ? -1
218
+ : (a.workflowKey ?? "") > (b.workflowKey ?? "")
219
+ ? 1
220
+ : 0) ||
221
+ (a.resource < b.resource ? -1 : a.resource > b.resource ? 1 : 0));
222
+ return {
223
+ windowDays,
224
+ apps: results.length,
225
+ workflowCount,
226
+ runsInWindow,
227
+ items,
228
+ syncCallable: syncCallable.sort(byAppThenKey),
229
+ idleWorkflows: idleWorkflows.sort(byAppThenKey),
230
+ truncated: truncated.sort(byAppThenKey),
231
+ errors,
232
+ complete,
233
+ };
234
+ }
235
+ const NONE = " (none)";
236
+ function refLine(ref, appId) {
237
+ const prefix = appId ? `${appId}/` : "";
238
+ return ` ${prefix}${ref.workflowKey} (${ref.workflowId})`;
239
+ }
240
+ function listBlock(title, refs) {
241
+ return {
242
+ heading: `${title} (${refs.length})`,
243
+ body: refs.length ? refs.map((ref) => refLine(ref, ref.appId)).join("\n") : NONE,
244
+ };
245
+ }
246
+ function errorLine(entry) {
247
+ const prefix = entry.appId ? `${entry.appId}/` : "";
248
+ const subject = entry.workflowKey
249
+ ? `${prefix}${entry.workflowKey} (${entry.workflowId})`
250
+ : (entry.appId ?? "");
251
+ return ` ${subject} ${entry.resource}: ${entry.message}`;
252
+ }
253
+ function errorBlock(entries) {
254
+ return {
255
+ heading: `Errors (${entries.length})`,
256
+ body: entries.length ? entries.map(errorLine).join("\n") : NONE,
257
+ };
258
+ }
259
+ /**
260
+ * The single-app table: the audit script's sections, in the script's order,
261
+ * in the CLI's `formatTable` idiom.
262
+ */
263
+ export function renderUsageReport(report) {
264
+ return [
265
+ {
266
+ body: `workflows ${report.workflowCount} ` +
267
+ `runs in window ${report.runsInWindow} ` +
268
+ `window ${report.windowDays} days`,
269
+ },
270
+ {
271
+ heading: "Step kinds",
272
+ body: formatTable(report.items, [
273
+ { header: "KIND", key: "kind" },
274
+ { header: "WORKFLOWS", key: "workflows", align: "right" },
275
+ { header: "RUNS", key: "runs", align: "right" },
276
+ ]),
277
+ },
278
+ listBlock("Sync-callable workflows", report.syncCallable),
279
+ listBlock("Idle workflows (no runs in window)", report.idleWorkflows),
280
+ listBlock("Truncated workflows (run scan cap reached)", report.truncated),
281
+ errorBlock(report.errors),
282
+ ];
283
+ }
284
+ /** The merged table: the same sections, with an APPS column and `appId/` refs. */
285
+ export function renderMergedUsageReport(report) {
286
+ return [
287
+ {
288
+ body: `apps ${report.apps} ` +
289
+ `workflows ${report.workflowCount} ` +
290
+ `runs in window ${report.runsInWindow} ` +
291
+ `window ${report.windowDays} days`,
292
+ },
293
+ {
294
+ heading: "Step kinds",
295
+ body: formatTable(report.items, [
296
+ { header: "KIND", key: "kind" },
297
+ { header: "WORKFLOWS", key: "workflows", align: "right" },
298
+ { header: "APPS", key: "apps", align: "right" },
299
+ { header: "RUNS", key: "runs", align: "right" },
300
+ ]),
301
+ },
302
+ listBlock("Sync-callable workflows", report.syncCallable),
303
+ listBlock("Idle workflows (no runs in window)", report.idleWorkflows),
304
+ listBlock("Truncated workflows (run scan cap reached)", report.truncated),
305
+ errorBlock(report.errors),
306
+ ];
307
+ }
308
+ /** An incomplete report is still printed — and still fails (intent). */
309
+ export function usageExitCode(report) {
310
+ return report.complete ? 0 : 1;
311
+ }
312
+ //# sourceMappingURL=workflow-usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-usage.js","sourceRoot":"","sources":["../../../src/lib/workflow-usage.ts"],"names":[],"mappings":"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"}
@@ -7,8 +7,6 @@ export interface Credentials {
7
7
  email: string;
8
8
  role: "admin" | "super-admin";
9
9
  name?: string;
10
- currentAppId?: string;
11
- currentAppName?: string;
12
10
  globalAdminAppId?: string;
13
11
  }
14
12
  export interface AppSummary {
@@ -353,7 +351,10 @@ export interface AnalyticsTopUsersResponse {
353
351
  limit: number;
354
352
  results: Array<{
355
353
  userUlid: string;
354
+ /** First event ever recorded for the user — does not move with windowDays (#3126). */
356
355
  firstSeen: string;
356
+ /** First event inside windowDays — the window-relative counterpart. */
357
+ firstSeenInWindow: string;
357
358
  lastSeen: string;
358
359
  eventCount: number;
359
360
  }>;
@@ -577,5 +578,14 @@ export interface SyncState {
577
578
  contentHash?: string;
578
579
  semanticHash?: string;
579
580
  }>;
581
+ functions?: Record<string, {
582
+ id: string;
583
+ modifiedAt: string;
584
+ contentHash?: string;
585
+ semanticHash?: string;
586
+ envelopeHash?: string;
587
+ activeConfigId?: string;
588
+ sources?: string[];
589
+ }>;
580
590
  };
581
591
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "primitive-admin",
3
- "version": "1.1.0-alpha.73",
3
+ "version": "1.1.0-alpha.74",
4
4
  "description": "CLI for administering Primitive applications",
5
5
  "type": "module",
6
6
  "bin": {
@@ -58,6 +58,7 @@
58
58
  "@inquirer/search": "^4.1.0",
59
59
  "chalk": "^5.3.0",
60
60
  "commander": "^12.1.0",
61
+ "esbuild": "0.25.12",
61
62
  "inquirer": "^9.2.12",
62
63
  "js-bao": "^0.5.1",
63
64
  "mime-types": "^2.1.35",