@wtfalch/foundry 0.16.15 → 0.17.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 (64) hide show
  1. package/dist/apply.d.ts +22 -1
  2. package/dist/bootstrap/bootstrap.d.ts +6 -1
  3. package/dist/bootstrap/bootstrap.js +26 -3
  4. package/dist/bootstrap/declare.d.ts +11 -1
  5. package/dist/bootstrap/declare.js +12 -2
  6. package/dist/index.d.ts +9 -4
  7. package/dist/index.js +7 -0
  8. package/dist/migrations/0038_calls_version_pin.sql +8 -0
  9. package/dist/migrations/0039_destroy_record.sql +7 -0
  10. package/dist/migrations/0040_company_included_uuid.sql +72 -0
  11. package/dist/migrations/0041_company_included_uuid_keys.sql +132 -0
  12. package/dist/migrations/0042_mutation_leases.sql +12 -0
  13. package/dist/org.d.ts +82 -5
  14. package/dist/org.js +62 -1
  15. package/dist/plan/adopt.d.ts +76 -0
  16. package/dist/plan/adopt.js +184 -0
  17. package/dist/plan/agora.d.ts +21 -0
  18. package/dist/plan/agora.js +37 -0
  19. package/dist/plan/broker-entries.d.ts +9 -1
  20. package/dist/plan/broker-entries.js +13 -5
  21. package/dist/plan/chat-matrix.d.ts +1 -1
  22. package/dist/plan/chat-matrix.js +11 -3
  23. package/dist/plan/core-files.d.ts +25 -0
  24. package/dist/plan/core-files.js +25 -0
  25. package/dist/plan/deploy-health.d.ts +136 -0
  26. package/dist/plan/deploy-health.js +153 -0
  27. package/dist/plan/diff.d.ts +11 -3
  28. package/dist/plan/diff.js +77 -71
  29. package/dist/plan/entry-ai-key.d.ts +3 -3
  30. package/dist/plan/entry-files-key.d.ts +6 -4
  31. package/dist/plan/entry-files-key.js +7 -10
  32. package/dist/plan/executor.d.ts +109 -28
  33. package/dist/plan/executor.js +213 -56
  34. package/dist/plan/hostnames.d.ts +6 -0
  35. package/dist/plan/hostnames.js +13 -0
  36. package/dist/plan/index.d.ts +5 -1
  37. package/dist/plan/index.js +3 -1
  38. package/dist/plan/live.d.ts +5 -0
  39. package/dist/plan/login-host.d.ts +1 -1
  40. package/dist/plan/login-host.js +6 -5
  41. package/dist/plan/plan-apply.d.ts +153 -3
  42. package/dist/plan/plan-apply.js +584 -69
  43. package/dist/plan/platform-diff.d.ts +103 -9
  44. package/dist/plan/platform-diff.js +192 -14
  45. package/dist/plan/platform-org.d.ts +25 -0
  46. package/dist/plan/platform-org.js +17 -1
  47. package/dist/plan/platform-providers.d.ts +38 -5
  48. package/dist/plan/platform-providers.js +592 -109
  49. package/dist/plan/providers-readers.d.ts +2 -0
  50. package/dist/plan/providers-readers.js +4 -0
  51. package/dist/plan/rollout.d.ts +52 -0
  52. package/dist/plan/rollout.js +37 -0
  53. package/dist/plan/step-system.d.ts +22 -0
  54. package/dist/plan/step-system.js +37 -0
  55. package/dist/plan.d.ts +3 -0
  56. package/dist/state.d.ts +13 -0
  57. package/dist/store/audit.js +15 -1
  58. package/dist/store/postgres.d.ts +1 -1
  59. package/dist/store/postgres.js +127 -14
  60. package/dist/store/schema.d.ts +134 -5
  61. package/dist/store/schema.js +12 -1
  62. package/dist/store.d.ts +47 -4
  63. package/dist/store.js +9 -1
  64. package/package.json +2 -2
@@ -1,4 +1,4 @@
1
- import { bigserial, boolean, integer, jsonb, pgTable, text, timestamp } from 'drizzle-orm/pg-core';
1
+ import { bigint, bigserial, boolean, integer, jsonb, pgTable, text, timestamp, } from 'drizzle-orm/pg-core';
2
2
  /**
3
3
  * Mirrors `migrations/0001_declared_org.sql`, which is the source of truth:
4
4
  * the SQL carries the CHECKs drizzle-kit does not generate here (this
@@ -31,6 +31,9 @@ export const declaredOrgs = pgTable('foundry_declared_orgs', {
31
31
  chatUsesDomain: boolean('chat_uses_domain').notNull().default(false),
32
32
  callsEnabled: boolean('calls_enabled').notNull().default(false),
33
33
  callsUsesDomain: boolean('calls_uses_domain').notNull().default(false),
34
+ // #259: null holds no pin -- the stack follows versions.json, same as today.
35
+ callsVersionPinSynapse: text('calls_version_pin_synapse'),
36
+ callsVersionPinMas: text('calls_version_pin_mas'),
34
37
  issuerUsesDomain: boolean('issuer_uses_domain').notNull().default(false),
35
38
  // SiteConfig (org.ts, T10). A brand new org has no cms site.
36
39
  siteEnabled: boolean('site_enabled').notNull().default(false),
@@ -101,6 +104,14 @@ export const foundryAppliedState = pgTable('foundry_applied_state', {
101
104
  failedFields: jsonb('failed_fields').notNull().default([]).$type(),
102
105
  lastAppliedAt: timestamp('last_applied_at', { withTimezone: true }),
103
106
  lastAppliedDeclaredOrgVersion: text('last_applied_declared_org_version'),
107
+ destroy: jsonb('destroy').$type(),
108
+ });
109
+ /** Mirrors `migrations/0042_mutation_leases.sql`: one row per lock scope; `token` only ever rises (#441). */
110
+ export const foundryMutationLeases = pgTable('foundry_mutation_leases', {
111
+ scope: text('scope').primaryKey(),
112
+ token: bigint('token', { mode: 'number' }).notNull(),
113
+ holder: text('holder').notNull(),
114
+ expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
104
115
  });
105
116
  /**
106
117
  * Mirrors `migrations/0036_applied_versions.sql`, the source of truth: an
package/dist/store.d.ts CHANGED
@@ -13,6 +13,24 @@ export interface StaleUpdate {
13
13
  /** The org as it stands now. */
14
14
  current: DeclaredOrg;
15
15
  }
16
+ /**
17
+ * A held mutation lease (#441). `token` rises on every acquire of a scope, so
18
+ * a worker whose lease expired and was taken over holds a token the store no
19
+ * longer accepts: its fenced writes are refused.
20
+ */
21
+ export interface MutationLease {
22
+ scope: string;
23
+ token: number;
24
+ }
25
+ /** What `acquireMutationLease` returns while another holder has the scope: when that lease runs out. */
26
+ export interface HeldLease {
27
+ heldUntil: Date;
28
+ }
29
+ /** A fenced write (`putAppliedState`, `putServiceIds`) came from a lease that is no longer the current one (#441). Nothing was written. */
30
+ export declare class StaleLeaseError extends Error {
31
+ readonly scope: string;
32
+ constructor(scope: string);
33
+ }
16
34
  /**
17
35
  * The persistence seam https://github.com/wtfalch/foundry/issues/18
18
36
  * implements: create, read and edit a {@link DeclaredOrg}, and read and
@@ -44,6 +62,12 @@ export interface DeclaredOrgStore {
44
62
  * record instead.
45
63
  */
46
64
  findOrgIdForZone(zoneId: string): Promise<OrgId | null>;
65
+ /**
66
+ * Archon#271: an org other than `exceptOrgId` whose applied state records
67
+ * `id` as a Coolify app, database or project, or `null`. Adopt refuses a
68
+ * resource another org already holds.
69
+ */
70
+ findOtherOrgRecordingCoolifyId(id: string, exceptOrgId: OrgId): Promise<OrgId | null>;
47
71
  /**
48
72
  * Combinations foundry knows are impossible are rejected with a reason
49
73
  * (#18 "Done when"), so a caller must be ready for this to throw rather
@@ -58,7 +82,26 @@ export interface DeclaredOrgStore {
58
82
  */
59
83
  update(id: OrgId, patch: Partial<DeclaredOrg>, opts: UpdateOptions): Promise<DeclaredOrg | StaleUpdate>;
60
84
  getAppliedState(id: OrgId): Promise<AppliedState | null>;
61
- putAppliedState(state: AppliedState): Promise<void>;
85
+ /**
86
+ * With `fence` (#441), compare-and-set: the write happens only while
87
+ * `fence.token` is still the scope's current lease token, otherwise it
88
+ * throws {@link StaleLeaseError} and writes nothing.
89
+ */
90
+ putAppliedState(state: AppliedState, fence?: MutationLease): Promise<void>;
91
+ /**
92
+ * #441: takes the exclusive mutation lease for `scope` (`company:<orgId>`
93
+ * or `platform`), or returns {@link HeldLease} while another holder's lease
94
+ * has not expired. Every successful acquire issues a higher token than the last.
95
+ */
96
+ acquireMutationLease(scope: string, holder: string, ttlMs: number): Promise<MutationLease | HeldLease>;
97
+ /**
98
+ * Extends the lease to `ttlMs` from now, only while `lease.token` is still
99
+ * the scope's current token. Returns false once it is not: the holder lost
100
+ * the scope and must stop before its next provider step.
101
+ */
102
+ renewMutationLease(lease: MutationLease, ttlMs: number): Promise<boolean>;
103
+ /** Frees the lease at once. A no-op if the lease was already taken over. */
104
+ releaseMutationLease(lease: MutationLease): Promise<void>;
62
105
  /**
63
106
  * Removes the declared org and its applied state together. Called only by
64
107
  * `FoundryPlanApply.destroy` (`plan/plan-apply.ts`), once every resource it
@@ -68,7 +111,7 @@ export interface DeclaredOrgStore {
68
111
  * not an error, so a retried destroy that reaches this step twice never
69
112
  * throws.
70
113
  */
71
- delete(id: OrgId): Promise<void>;
114
+ delete(id: OrgId, fence?: MutationLease): Promise<void>;
72
115
  }
73
116
  /**
74
117
  * The persistence seam for #166's {@link DeclaredPlatform}, mirroring
@@ -87,8 +130,8 @@ export interface PlatformStore {
87
130
  * before the first apply. `put` never touches it.
88
131
  */
89
132
  getServiceIds(): Promise<Record<string, string>>;
90
- /** Replaces the recorded ids. A no-op until the platform is declared. */
91
- putServiceIds(serviceIds: Record<string, string>): Promise<void>;
133
+ /** Replaces the recorded ids. A no-op until the platform is declared. With `fence` (#441), compare-and-set as {@link DeclaredOrgStore.putAppliedState}. */
134
+ putServiceIds(serviceIds: Record<string, string>, fence?: MutationLease): Promise<void>;
92
135
  }
93
136
  /**
94
137
  * One recorded apply, appended to the history #253 keeps beside
package/dist/store.js CHANGED
@@ -1 +1,9 @@
1
- export {};
1
+ /** A fenced write (`putAppliedState`, `putServiceIds`) came from a lease that is no longer the current one (#441). Nothing was written. */
2
+ export class StaleLeaseError extends Error {
3
+ scope;
4
+ constructor(scope) {
5
+ super(`mutation lease for ${scope} was lost to a newer holder; nothing written`);
6
+ this.scope = scope;
7
+ this.name = 'StaleLeaseError';
8
+ }
9
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wtfalch/foundry",
3
- "version": "0.16.15",
3
+ "version": "0.17.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",
@@ -43,7 +43,7 @@
43
43
  "@wtfalch/audit": "0.6.0",
44
44
  "@wtfalch/auth": "0.16.0",
45
45
  "@wtfalch/email": "^0.17.0",
46
- "@wtfalch/providers": "0.7.2",
46
+ "@wtfalch/providers": "0.7.3",
47
47
  "ssh2": "1.17.0",
48
48
  "zod": "4.6.5"
49
49
  },