@wtfalch/foundry 0.62.0 → 0.64.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/dist/apps/index.d.ts +1 -0
  2. package/dist/apps/index.js +1 -0
  3. package/dist/apps/server-entry.d.ts +43 -0
  4. package/dist/apps/server-entry.js +99 -0
  5. package/dist/bootstrap/declare.js +4 -1
  6. package/dist/bootstrap/versions.d.ts +2 -0
  7. package/dist/build-json.d.ts +25 -0
  8. package/dist/build-json.js +61 -0
  9. package/dist/catalogue/copy-en.js +10 -0
  10. package/dist/catalogue/integrations.js +10 -0
  11. package/dist/index.d.ts +8 -4
  12. package/dist/index.js +3 -2
  13. package/dist/migrations/0067_requested_changes_kosmos.sql +6 -0
  14. package/dist/migrations/0068_platform_registry.sql +17 -0
  15. package/dist/modules/customer-grants.d.ts +3 -0
  16. package/dist/modules/customer-grants.js +28 -0
  17. package/dist/modules/index.js +49 -1
  18. package/dist/modules/repository.d.ts +6 -0
  19. package/dist/modules/repository.js +40 -0
  20. package/dist/modules/types.d.ts +8 -0
  21. package/dist/native-build.d.ts +7 -27
  22. package/dist/native-build.js +7 -27
  23. package/dist/org.d.ts +19 -1
  24. package/dist/org.js +45 -3
  25. package/dist/plan/archon-blue-green.d.ts +5 -0
  26. package/dist/plan/archon-blue-green.js +2 -0
  27. package/dist/plan/blue-green-apply.d.ts +5 -0
  28. package/dist/plan/blue-green-apply.js +197 -22
  29. package/dist/plan/blue-green.d.ts +61 -2
  30. package/dist/plan/blue-green.js +80 -6
  31. package/dist/plan/boule.d.ts +1 -1
  32. package/dist/plan/boule.js +2 -0
  33. package/dist/plan/broker-entries.d.ts +9 -0
  34. package/dist/plan/broker-entries.js +29 -0
  35. package/dist/plan/diff.d.ts +5 -0
  36. package/dist/plan/diff.js +21 -2
  37. package/dist/plan/edge-access.d.ts +2 -3
  38. package/dist/plan/edge-access.js +7 -0
  39. package/dist/plan/executor.d.ts +71 -1
  40. package/dist/plan/executor.js +491 -56
  41. package/dist/plan/index.d.ts +2 -0
  42. package/dist/plan/index.js +1 -0
  43. package/dist/plan/jobs-scheduler-http.d.ts +2 -0
  44. package/dist/plan/jobs-scheduler-http.js +11 -0
  45. package/dist/plan/own-limits.d.ts +6 -0
  46. package/dist/plan/own-limits.js +1 -0
  47. package/dist/plan/plan-apply.d.ts +51 -1
  48. package/dist/plan/plan-apply.js +298 -25
  49. package/dist/plan/platform-diff.d.ts +23 -1
  50. package/dist/plan/platform-diff.js +96 -0
  51. package/dist/plan/platform-org.d.ts +2 -0
  52. package/dist/plan/platform-providers.d.ts +46 -1
  53. package/dist/plan/platform-providers.js +156 -1
  54. package/dist/plan/platform-registry-keys.d.ts +58 -0
  55. package/dist/plan/platform-registry-keys.js +69 -0
  56. package/dist/plan/platform-registry.d.ts +67 -0
  57. package/dist/plan/platform-registry.js +298 -0
  58. package/dist/plan/release-host.d.ts +31 -2
  59. package/dist/plan/release-host.js +114 -6
  60. package/dist/plan/stage-copy-host.d.ts +104 -0
  61. package/dist/plan/stage-copy-host.js +259 -0
  62. package/dist/plan/stage-copy.js +44 -0
  63. package/dist/plan/stage-env.d.ts +9 -0
  64. package/dist/plan/stage-env.js +38 -0
  65. package/dist/plan/stage-guards.d.ts +57 -1
  66. package/dist/plan/stage-guards.js +106 -0
  67. package/dist/plan/stage-isolation.js +56 -0
  68. package/dist/plan/stage-services.d.ts +93 -0
  69. package/dist/plan/stage-services.js +153 -0
  70. package/dist/plan/stage-signin.d.ts +152 -0
  71. package/dist/plan/stage-signin.js +133 -0
  72. package/dist/plan/stage-sink.d.ts +2 -0
  73. package/dist/plan/stage-sink.js +6 -1
  74. package/dist/platform.d.ts +7 -1
  75. package/dist/platform.js +1 -0
  76. package/dist/release/decide.d.ts +12 -0
  77. package/dist/release/decide.js +37 -2
  78. package/dist/release/run.d.ts +71 -1
  79. package/dist/release/run.js +92 -8
  80. package/dist/release/state.d.ts +14 -1
  81. package/dist/release/state.js +43 -0
  82. package/dist/release/types.d.ts +20 -0
  83. package/dist/release/types.js +2 -0
  84. package/dist/requested-changes.d.ts +11 -2
  85. package/dist/requested-changes.js +11 -0
  86. package/dist/store/postgres.js +8 -0
  87. package/dist/store/schema.d.ts +51 -0
  88. package/dist/store/schema.js +4 -0
  89. package/package.json +3 -2
  90. package/versions.digests.json +1 -0
  91. package/versions.json +1 -0
@@ -51,6 +51,20 @@ export interface ReleaseState {
51
51
  signal: ReleaseSignal | null;
52
52
  held: string[];
53
53
  config: ReleaseConfig;
54
+ /** The last stage copy request's outcome (`bg.<id>.stagecopy`); absent before the first. */
55
+ stageCopy?: StageCopyState;
56
+ /** The last `deploy_stage`: when, whether it worked, and the commit (ok) or the step that failed. */
57
+ stageDeploy?: {
58
+ at: string;
59
+ outcome: 'ok' | 'failed';
60
+ detail: string;
61
+ };
62
+ }
63
+ /** C3: what the last `copy_prod_to_stage` or `undo_stage_copy` request did. `detail` is fixed text or an id. */
64
+ export interface StageCopyState {
65
+ at: string;
66
+ outcome: 'ok' | 'refused' | 'failed';
67
+ detail: string;
54
68
  }
55
69
  export type ReleaseAction = {
56
70
  kind: 'promote';
@@ -69,6 +83,12 @@ export type ReleaseAction = {
69
83
  } | {
70
84
  kind: 'deploy_stage';
71
85
  ref: string;
86
+ } | {
87
+ kind: 'copy_prod_to_stage';
88
+ } | {
89
+ kind: 'undo_stage_copy';
72
90
  };
91
+ /** The requests that run a stage copy. They are handled by the tick's second phase, never by an apply. */
92
+ export declare const isStageCopyAction: (action: ReleaseAction) => boolean;
73
93
  export declare const COLORS: readonly Color[];
74
94
  export declare function otherColor(color: Color): Color;
@@ -1,3 +1,5 @@
1
+ /** The requests that run a stage copy. They are handled by the tick's second phase, never by an apply. */
2
+ export const isStageCopyAction = (action) => action.kind === 'copy_prod_to_stage' || action.kind === 'undo_stage_copy';
1
3
  export const COLORS = ['blue', 'green'];
2
4
  export function otherColor(color) {
3
5
  return color === 'blue' ? 'green' : 'blue';
@@ -16,7 +16,7 @@ import type { PlanDetail } from './plan/diff.js';
16
16
  * lowering or leaving a limit unchanged -- raising either one needs
17
17
  * approval too, until a billing field exists to say what the raise costs.
18
18
  */
19
- export type RequestableField = 'calls' | 'customers' | 'storageLimit' | 'aiLimit' | 'domain' | 'mailTier' | 'app' | 'build' | 'bouleApps';
19
+ export type RequestableField = 'calls' | 'customers' | 'storageLimit' | 'aiLimit' | 'domain' | 'mailTier' | 'app' | 'build' | 'bouleApps' | 'kosmos';
20
20
  export declare const REQUESTABLE_FIELDS: readonly RequestableField[];
21
21
  /** Turn the org's own calls Matrix stack (`org.ts`'s `CallsConfig.enabled`) on or off. */
22
22
  export interface CallsChange {
@@ -84,12 +84,21 @@ export interface BouleAppsChange {
84
84
  field: 'bouleApps';
85
85
  enabled: boolean;
86
86
  }
87
+ /**
88
+ * Turn `org.kosmos.enabled` on or off (`org.ts`'s `KosmosApp.enabled`). On provisions only what kosmos needs
89
+ * (its ZITADEL client, its database, its live and idle copies) -- auto. Off retires its app, database route and
90
+ * ZITADEL client (steps marked `destroys: true`), so it always needs a person, same shape as `bouleApps`.
91
+ */
92
+ export interface KosmosChange {
93
+ field: 'kosmos';
94
+ enabled: boolean;
95
+ }
87
96
  /**
88
97
  * One company-requested change to its own declared org, keyed by
89
98
  * {@link RequestableField}. `classifyChange` and the store both switch on
90
99
  * `.field`.
91
100
  */
92
- export type RequestedChangeValue = CallsChange | CustomersChange | StorageLimitChange | AiLimitChange | DomainChange | MailTierChange | AppChange | BuildChange | BouleAppsChange;
101
+ export type RequestedChangeValue = CallsChange | CustomersChange | StorageLimitChange | AiLimitChange | DomainChange | MailTierChange | AppChange | BuildChange | BouleAppsChange | KosmosChange;
93
102
  /**
94
103
  * `auto`: nothing further is required -- archon may carry the request
95
104
  * straight into a plan and apply it. `approval`: a human must approve the
@@ -9,6 +9,7 @@ export const REQUESTABLE_FIELDS = [
9
9
  'app',
10
10
  'build',
11
11
  'bouleApps',
12
+ 'kosmos',
12
13
  ];
13
14
  /**
14
15
  * Thrown by {@link classifyChange} (and by the requested-change store's
@@ -47,6 +48,8 @@ function applyRequestedChange(org, change) {
47
48
  return { ...org, mail: { ...org.mail, mode: change.mode } };
48
49
  case 'bouleApps':
49
50
  return { ...org, boule: { ...org.boule, apps: change.enabled } };
51
+ case 'kosmos':
52
+ return { ...org, kosmos: { ...org.kosmos, enabled: change.enabled } };
50
53
  case 'app':
51
54
  case 'build':
52
55
  return org;
@@ -135,6 +138,14 @@ export function classifyChange(org, change, plan) {
135
138
  // (`destroys: true` steps), so it needs a person whether or not a plan was given.
136
139
  return change.enabled ? 'auto' : 'approval';
137
140
  }
141
+ if (change.field === 'kosmos') {
142
+ if (typeof change.enabled !== 'boolean') {
143
+ throw new RequestedChangeError('kosmos needs enabled, true or false');
144
+ }
145
+ // Turning on provisions only what kosmos needs. Turning off retires its app, database route and
146
+ // ZITADEL client (`destroys: true` steps), so it needs a person whether or not a plan was given.
147
+ return change.enabled ? 'auto' : 'approval';
148
+ }
138
149
  if (change.field === 'customers') {
139
150
  validateCustomersChange(change);
140
151
  // The org after the change must still pass the rule apply checks, for example open registration
@@ -801,6 +801,11 @@ function rowToPlatform(row) {
801
801
  hostname: row.hcHostname,
802
802
  gitRef: row.hcGitRef,
803
803
  },
804
+ registry: {
805
+ enabled: row.registryEnabled,
806
+ hostname: row.registryHostname,
807
+ gitRef: row.registryGitRef,
808
+ },
804
809
  coolify: {
805
810
  enabled: row.coolifyEnabled,
806
811
  hostname: row.coolifyHostname,
@@ -850,6 +855,9 @@ function platformToRow(platform) {
850
855
  hcEnabled: platform.hc.enabled,
851
856
  hcHostname: platform.hc.hostname,
852
857
  hcGitRef: platform.hc.gitRef,
858
+ registryEnabled: platform.registry.enabled,
859
+ registryHostname: platform.registry.hostname,
860
+ registryGitRef: platform.registry.gitRef,
853
861
  coolifyEnabled: platform.coolify.enabled,
854
862
  coolifyHostname: platform.coolify.hostname,
855
863
  coolifyGitRef: platform.coolify.gitRef,
@@ -2292,6 +2292,57 @@ export declare const foundryDeclaredPlatform: import("drizzle-orm/pg-core").PgTa
2292
2292
  identity: undefined;
2293
2293
  generated: undefined;
2294
2294
  }, {}, {}>;
2295
+ registryEnabled: import("drizzle-orm/pg-core").PgColumn<{
2296
+ name: "registry_enabled";
2297
+ tableName: "foundry_declared_platform";
2298
+ dataType: "boolean";
2299
+ columnType: "PgBoolean";
2300
+ data: boolean;
2301
+ driverParam: boolean;
2302
+ notNull: true;
2303
+ hasDefault: true;
2304
+ isPrimaryKey: false;
2305
+ isAutoincrement: false;
2306
+ hasRuntimeDefault: false;
2307
+ enumValues: undefined;
2308
+ baseColumn: never;
2309
+ identity: undefined;
2310
+ generated: undefined;
2311
+ }, {}, {}>;
2312
+ registryHostname: import("drizzle-orm/pg-core").PgColumn<{
2313
+ name: "registry_hostname";
2314
+ tableName: "foundry_declared_platform";
2315
+ dataType: "string";
2316
+ columnType: "PgText";
2317
+ data: string;
2318
+ driverParam: string;
2319
+ notNull: true;
2320
+ hasDefault: false;
2321
+ isPrimaryKey: false;
2322
+ isAutoincrement: false;
2323
+ hasRuntimeDefault: false;
2324
+ enumValues: [string, ...string[]];
2325
+ baseColumn: never;
2326
+ identity: undefined;
2327
+ generated: undefined;
2328
+ }, {}, {}>;
2329
+ registryGitRef: import("drizzle-orm/pg-core").PgColumn<{
2330
+ name: "registry_git_ref";
2331
+ tableName: "foundry_declared_platform";
2332
+ dataType: "string";
2333
+ columnType: "PgText";
2334
+ data: string;
2335
+ driverParam: string;
2336
+ notNull: true;
2337
+ hasDefault: true;
2338
+ isPrimaryKey: false;
2339
+ isAutoincrement: false;
2340
+ hasRuntimeDefault: false;
2341
+ enumValues: [string, ...string[]];
2342
+ baseColumn: never;
2343
+ identity: undefined;
2344
+ generated: undefined;
2345
+ }, {}, {}>;
2295
2346
  coolifyEnabled: import("drizzle-orm/pg-core").PgColumn<{
2296
2347
  name: "coolify_enabled";
2297
2348
  tableName: "foundry_declared_platform";
@@ -219,6 +219,10 @@ export const foundryDeclaredPlatform = pgTable('foundry_declared_platform', {
219
219
  hcEnabled: boolean('hc_enabled').notNull().default(false),
220
220
  hcHostname: text('hc_hostname').notNull(),
221
221
  hcGitRef: text('hc_git_ref').notNull().default(''),
222
+ /** `migrations/0067_platform_registry.sql`: the platform's image registry. */
223
+ registryEnabled: boolean('registry_enabled').notNull().default(false),
224
+ registryHostname: text('registry_hostname').notNull(),
225
+ registryGitRef: text('registry_git_ref').notNull().default(''),
222
226
  /** `migrations/0047_platform_coolify.sql`: the Coolify panel's declared address; foundry never deploys it. */
223
227
  coolifyEnabled: boolean('coolify_enabled').notNull().default(false),
224
228
  coolifyHostname: text('coolify_hostname').notNull(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wtfalch/foundry",
3
- "version": "0.62.0",
3
+ "version": "0.64.0",
4
4
  "description": "Foundry's SDK: the declared org's types, the plan and apply contracts, and the state store's interface.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -61,9 +61,10 @@
61
61
  "@wtfalch/audit": "0.6.0",
62
62
  "@wtfalch/audit-sealing": "npm:@wtfalch/audit@0.14.0",
63
63
  "@wtfalch/auth": "^0.26.0",
64
- "@wtfalch/edge": "0.21.0",
64
+ "@wtfalch/edge": "0.23.0",
65
65
  "@wtfalch/email": "^0.20.0",
66
66
  "@wtfalch/providers": "0.12.0",
67
+ "bcryptjs": "3.0.3",
67
68
  "ssh2": "1.17.0",
68
69
  "zod": "4.6.5"
69
70
  },
@@ -6,6 +6,7 @@
6
6
  "cloudflared": "sha256:072c067d25ccbe61d46e18f0d0723255f2bb5304f7317caa95b27031520ff92c",
7
7
  "stalwart": "sha256:ec011be228596e37e65f41aab17deed573859614430472f7eeb42178c50d87b7",
8
8
  "hc": "sha256:aa08a61b0dcfd83f1332eab195d5cec1b595ae076eb8388cadf8a3d597114f9b",
9
+ "registry": "sha256:01cd312e67026f06f5d89c3e133a4a9adc7cb9eeb9b1194e0b2954dfd770efd2",
9
10
  "alpine": "sha256:4bcff63911fcb4448bd4fdacec207030997caf25e9bea4045fa6c8c44de311d1",
10
11
  "busybox": "sha256:5cec3fc171c87218698e85a52af7087de727372aae264a787b8112901a5b0092",
11
12
  "postgres": "sha256:786dab398303b8ce7cb76b407bb21ef2e4dfbbbd4c6abcf3d29b3130467ffdbc",
package/versions.json CHANGED
@@ -6,6 +6,7 @@
6
6
  "cloudflared": "2026.9.3",
7
7
  "stalwart": "v0.16.24",
8
8
  "hc": "v4.4",
9
+ "registry": "3.1.2",
9
10
  "alpine": "3.22.1",
10
11
  "busybox": "1.37.0-musl",
11
12
  "postgres": "16.14-alpine3.22",