@feltdb/core 0.7.4 → 0.8.1
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/README.md +25 -0
- package/dist/application-development.d.ts +10 -3
- package/dist/application-development.d.ts.map +1 -1
- package/dist/application-development.js +11 -1
- package/dist/application-manifest.d.ts +2 -0
- package/dist/application-manifest.d.ts.map +1 -1
- package/dist/application-manifest.js +1 -1
- package/dist/application-understanding.d.ts +76 -0
- package/dist/application-understanding.d.ts.map +1 -0
- package/dist/application-understanding.js +282 -0
- package/dist/canonical-application.d.ts +1 -0
- package/dist/canonical-application.d.ts.map +1 -1
- package/dist/canonical-application.js +3 -2
- package/dist/cli/ai-model-config.js +3 -3
- package/dist/cli/cli.js +1 -1
- package/dist/cli/commands.js +321 -45
- package/dist/cli/index.js +1 -1
- package/dist/cli/managed-environment.js +6 -0
- package/dist/cli/managed-project.js +6 -0
- package/dist/cli/proposal-client.js +16 -3
- package/dist/cli/publish-engine.js +8 -5
- package/dist/cli/repository-evidence.js +55 -0
- package/dist/cli/source-sync.js +220 -61
- package/dist/convergence.d.ts +55 -0
- package/dist/convergence.d.ts.map +1 -0
- package/dist/convergence.js +63 -0
- package/dist/create/cli.js +10 -1
- package/dist/create/create.js +10 -12
- package/dist/create/managed-account.js +72 -7
- package/dist/create/package-versions.js +1 -1
- package/dist/create/server-source/crates/feltdb/src/application.rs +14 -0
- package/dist/create/server-source/crates/feltdb/src/lib.rs +20 -2
- package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +12 -24
- package/dist/create/server-source/crates/feltdb-server/src/application_contract.rs +11 -3
- package/dist/create/server-source/crates/feltdb-server/src/authenticated_principal.rs +0 -1
- package/dist/create/server-source/crates/feltdb-server/src/certification_harness.rs +23 -22
- package/dist/create/server-source/crates/feltdb-server/src/connections.rs +14 -0
- package/dist/create/server-source/crates/feltdb-server/src/delegation_token.rs +5 -15
- package/dist/create/server-source/crates/feltdb-server/src/durable_operations.rs +13 -28
- package/dist/create/server-source/crates/feltdb-server/src/identity.rs +79 -14
- package/dist/create/server-source/crates/feltdb-server/src/key_management.rs +28 -7
- package/dist/create/server-source/crates/feltdb-server/src/lib.rs +5 -5
- package/dist/create/server-source/crates/feltdb-server/src/main.rs +1929 -261
- package/dist/create/server-source/crates/feltdb-server/src/managed_diagnostics.rs +10 -30
- package/dist/create/server-source/crates/feltdb-server/src/membership_policy.rs +12 -4
- package/dist/create/server-source/crates/feltdb-server/src/request_telemetry.rs +8 -6
- package/dist/create/server-source/crates/feltdb-server/src/snapshot_cursor.rs +10 -14
- package/dist/create/server-source/crates/feltdb-server/src/tenancy.rs +191 -22
- package/dist/create/server-source/crates/feltdb-server/src/tenant_policies.rs +9 -21
- package/dist/create/server-source/crates/feltdb-server/src/transaction_idempotency.rs +5 -3
- package/dist/create/server-source/crates/feltdb-server/src/transaction_recovery.rs +9 -8
- package/dist/create/server-source/crates/feltdb-server/tests/revision_recovery_integration_test.rs +1 -4
- package/dist/create/template/default-project/feltdb.flow +5 -0
- package/dist/create/template/default-project/src/context/AuthContext.tsx +9 -1
- package/dist/create/template/default-project/src/pages/SignUp.tsx +1 -1
- package/dist/flowspec.d.ts +1 -0
- package/dist/flowspec.d.ts.map +1 -1
- package/dist/flowspec.js +51 -12
- package/dist/http-client.d.ts +166 -14
- package/dist/http-client.d.ts.map +1 -1
- package/dist/http-client.js +91 -31
- package/dist/http-db.d.ts +3 -0
- package/dist/http-db.d.ts.map +1 -1
- package/dist/http-db.js +28 -3
- package/dist/index-core.d.ts +5 -0
- package/dist/index-core.d.ts.map +1 -1
- package/dist/index-core.js +5 -0
- package/dist/intent.d.ts +98 -0
- package/dist/intent.d.ts.map +1 -0
- package/dist/intent.js +343 -0
- package/dist/module-intent.d.ts +51 -0
- package/dist/module-intent.d.ts.map +1 -0
- package/dist/module-intent.js +230 -0
- package/dist/module.d.ts +105 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +566 -0
- package/dist/proposal.d.ts +92 -4
- package/dist/proposal.d.ts.map +1 -1
- package/dist/proposal.js +150 -6
- package/dist/studio/app.d.ts +3 -1
- package/dist/studio/app.d.ts.map +1 -1
- package/dist/studio/components/AskFeltDB.d.ts +2 -1
- package/dist/studio/components/AskFeltDB.d.ts.map +1 -1
- package/dist/studio/components/ContractInspector.d.ts +7 -0
- package/dist/studio/components/ContractInspector.d.ts.map +1 -0
- package/dist/studio/components/ManagedInstancePanel.d.ts.map +1 -1
- package/dist/studio/components/ManagedInstancePanel.js +1 -5
- package/dist/studio/components/ModuleExplorer.d.ts +6 -0
- package/dist/studio/components/ModuleExplorer.d.ts.map +1 -0
- package/dist/studio/components/ProposalBrowser.d.ts +10 -1
- package/dist/studio/components/ProposalBrowser.d.ts.map +1 -1
- package/dist/studio/components/StateExplorer.d.ts +6 -7
- package/dist/studio/components/StateExplorer.d.ts.map +1 -1
- package/dist/studio/components/index.d.ts +2 -0
- package/dist/studio/components/index.d.ts.map +1 -1
- package/dist/studio/components/index.js +4 -4
- package/dist/studio/components-Duq2xQWt.js +2845 -0
- package/dist/studio/index.js +193 -147
- package/dist/studio/studio.css +1 -1
- package/dist/studio/utils/index.d.ts +2 -0
- package/dist/studio/utils/index.d.ts.map +1 -1
- package/dist/studio/utils/index.js +14 -12
- package/dist/studio/utils/managed-instance.d.ts +0 -4
- package/dist/studio/utils/managed-instance.d.ts.map +1 -1
- package/dist/studio/utils/managed-instance.js +0 -4
- package/dist/studio/utils/proposal-api.d.ts +56 -0
- package/dist/studio/utils/proposal-api.d.ts.map +1 -0
- package/dist/studio/utils/proposal-api.js +94 -0
- package/dist/studio/utils/service-api.d.ts +81 -0
- package/dist/studio/utils/service-api.d.ts.map +1 -0
- package/dist/studio/utils/service-api.js +51 -0
- package/dist/studio-app/assets/{feltdb_wasm-B-Ccgccb.js → feltdb_wasm-bIqcRzAr.js} +1 -1
- package/dist/studio-app/assets/feltdb_wasm_bg-BE79okwX.wasm +0 -0
- package/dist/studio-app/assets/{index-BRrmvaKw.css → index-Cd_NPw14.css} +1 -1
- package/dist/studio-app/assets/index-XGYdlElN.js +29 -0
- package/dist/studio-app/index.html +2 -2
- package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
- package/dist/workspace/local-development-authority.d.ts +2 -0
- package/dist/workspace/local-development-authority.d.ts.map +1 -1
- package/dist/workspace/local-development-authority.js +128 -4
- package/package.json +1 -1
- package/dist/studio/components-Bm4sjhcX.js +0 -2162
- package/dist/studio-app/assets/dist-DA1MYSzp.js +0 -1
- package/dist/studio-app/assets/feltdb_wasm_bg-wH3enJIA.wasm +0 -0
- package/dist/studio-app/assets/index-CEIqowCh.js +0 -42
- package/dist/studio-app/assets/lib-B2_7fcn7.js +0 -69
- package/dist/studio-app/assets/worker-CARZ5g7K.js +0 -69
package/dist/module.js
ADDED
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
const model = (name, ownership = "external-authoritative") => ({
|
|
2
|
+
name,
|
|
3
|
+
authority: "external",
|
|
4
|
+
ownership,
|
|
5
|
+
fields: [
|
|
6
|
+
{
|
|
7
|
+
name: "id",
|
|
8
|
+
type: "text",
|
|
9
|
+
immutable: true,
|
|
10
|
+
externally_owned: true,
|
|
11
|
+
application_readable: true,
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
name: "status",
|
|
15
|
+
type: "text",
|
|
16
|
+
optional: true,
|
|
17
|
+
externally_owned: true,
|
|
18
|
+
application_readable: true,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: "created_at",
|
|
22
|
+
type: "datetime",
|
|
23
|
+
externally_owned: true,
|
|
24
|
+
application_readable: true,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: "metadata",
|
|
28
|
+
type: "json",
|
|
29
|
+
optional: true,
|
|
30
|
+
externally_owned: true,
|
|
31
|
+
application_readable: true,
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
});
|
|
35
|
+
const stripe = {
|
|
36
|
+
id: "stripe",
|
|
37
|
+
name: "Stripe-compatible billing",
|
|
38
|
+
version: "1.0.0",
|
|
39
|
+
provider: "stripe-compatible",
|
|
40
|
+
compatibility: ["stripe", "stripe-compatible"],
|
|
41
|
+
intent_keywords: ["stripe", "billing", "plan", "subscription"],
|
|
42
|
+
models: [
|
|
43
|
+
"Customer",
|
|
44
|
+
"Product",
|
|
45
|
+
"Price",
|
|
46
|
+
"Subscription",
|
|
47
|
+
"SubscriptionItem",
|
|
48
|
+
"Invoice",
|
|
49
|
+
"PaymentIntent",
|
|
50
|
+
"CheckoutSession",
|
|
51
|
+
"PaymentMethod",
|
|
52
|
+
"Refund",
|
|
53
|
+
"WebhookEvent",
|
|
54
|
+
].map((name) => model(name)),
|
|
55
|
+
relationships: [
|
|
56
|
+
{ from: "Customer", to: "Subscription", kind: "many" },
|
|
57
|
+
{ from: "Subscription", to: "SubscriptionItem", kind: "many" },
|
|
58
|
+
{ from: "SubscriptionItem", to: "Price", kind: "one" },
|
|
59
|
+
{ from: "Price", to: "Product", kind: "one" },
|
|
60
|
+
{ from: "Customer", to: "Invoice", kind: "many" },
|
|
61
|
+
{ from: "Invoice", to: "PaymentIntent", kind: "one" },
|
|
62
|
+
],
|
|
63
|
+
events: [
|
|
64
|
+
"stripe.customer.created",
|
|
65
|
+
"stripe.customer.updated",
|
|
66
|
+
"stripe.subscription.created",
|
|
67
|
+
"stripe.subscription.updated",
|
|
68
|
+
"stripe.subscription.deleted",
|
|
69
|
+
"stripe.invoice.paid",
|
|
70
|
+
"stripe.invoice.payment_failed",
|
|
71
|
+
"stripe.checkout.session.completed",
|
|
72
|
+
],
|
|
73
|
+
capabilities: [
|
|
74
|
+
"stripe.customer.read",
|
|
75
|
+
"stripe.customer.create",
|
|
76
|
+
"stripe.checkout.create",
|
|
77
|
+
"stripe.subscription.read",
|
|
78
|
+
"stripe.subscription.create",
|
|
79
|
+
"stripe.subscription.cancel",
|
|
80
|
+
"stripe.invoice.read",
|
|
81
|
+
"stripe.webhooks.receive",
|
|
82
|
+
],
|
|
83
|
+
workflows: ["ReconcileSubscription", "ReconcileFailedPayment"],
|
|
84
|
+
configuration: [
|
|
85
|
+
{
|
|
86
|
+
name: "STRIPE_PUBLISHABLE_KEY",
|
|
87
|
+
required: false,
|
|
88
|
+
description: "Browser-safe publishable provider key",
|
|
89
|
+
visibility: "browser",
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
secrets: [
|
|
93
|
+
{
|
|
94
|
+
name: "STRIPE_SECRET_KEY",
|
|
95
|
+
required: true,
|
|
96
|
+
description: "Server-side provider credential",
|
|
97
|
+
visibility: "server",
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: "STRIPE_WEBHOOK_SECRET",
|
|
101
|
+
required: true,
|
|
102
|
+
environments: ["production"],
|
|
103
|
+
description: "Webhook signature verification secret",
|
|
104
|
+
visibility: "server",
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
validation: [
|
|
108
|
+
"Webhook receivers must verify signatures",
|
|
109
|
+
"Checkout creation requires authenticated authorization",
|
|
110
|
+
],
|
|
111
|
+
dependencies: [
|
|
112
|
+
{
|
|
113
|
+
name: "authentication",
|
|
114
|
+
description: "Checkout requires an authenticated application identity",
|
|
115
|
+
any_collections: ["User", "Account"],
|
|
116
|
+
any_capabilities: ["auth.session.read", "authentication"],
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
authorization: [
|
|
120
|
+
{
|
|
121
|
+
capability: "stripe.checkout.create",
|
|
122
|
+
subject: "authenticated",
|
|
123
|
+
implication: "A signed-in billing owner may create a hosted checkout session",
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
capability: "stripe.subscription.cancel",
|
|
127
|
+
subject: "owner",
|
|
128
|
+
implication: "Only the billing owner may cancel a subscription",
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
extension_application_models: [
|
|
132
|
+
{
|
|
133
|
+
name: "BillingPlan",
|
|
134
|
+
ownership: "application-authoritative",
|
|
135
|
+
purpose: "Application pricing and entitlement plan",
|
|
136
|
+
fields: [
|
|
137
|
+
{ name: "code", type: "text" },
|
|
138
|
+
{ name: "interval", type: "enum(monthly,annual)" },
|
|
139
|
+
{ name: "price", type: "ref $module.Price" },
|
|
140
|
+
{ name: "active", type: "boolean" },
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
patterns: [
|
|
145
|
+
{
|
|
146
|
+
name: "organization billing",
|
|
147
|
+
when: "The application contains an organizational owner",
|
|
148
|
+
owner_candidates: ["Organization", "Workspace"],
|
|
149
|
+
application_models: [
|
|
150
|
+
{
|
|
151
|
+
name: "BillingAccount",
|
|
152
|
+
ownership: "application-authoritative",
|
|
153
|
+
purpose: "Connect the application billing owner to provider state",
|
|
154
|
+
fields: [
|
|
155
|
+
{ name: "owner", type: "ref $owner" },
|
|
156
|
+
{ name: "customer", type: "ref $module.Customer" },
|
|
157
|
+
{
|
|
158
|
+
name: "subscription",
|
|
159
|
+
type: "ref $module.Subscription",
|
|
160
|
+
optional: true,
|
|
161
|
+
},
|
|
162
|
+
{ name: "status", type: "text" },
|
|
163
|
+
],
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
name: "Entitlement",
|
|
167
|
+
ownership: "derived",
|
|
168
|
+
purpose: "Materialize product access from reconciled subscription state",
|
|
169
|
+
fields: [
|
|
170
|
+
{ name: "billing_account", type: "ref BillingAccount" },
|
|
171
|
+
{ name: "key", type: "text" },
|
|
172
|
+
{ name: "active", type: "boolean" },
|
|
173
|
+
],
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: "user billing",
|
|
179
|
+
when: "The application is user-centric",
|
|
180
|
+
owner_candidates: ["User", "Account"],
|
|
181
|
+
application_models: [
|
|
182
|
+
{
|
|
183
|
+
name: "BillingAccount",
|
|
184
|
+
ownership: "application-authoritative",
|
|
185
|
+
purpose: "Connect the user to provider state",
|
|
186
|
+
fields: [
|
|
187
|
+
{ name: "owner", type: "ref $owner" },
|
|
188
|
+
{ name: "customer", type: "ref $module.Customer" },
|
|
189
|
+
{
|
|
190
|
+
name: "subscription",
|
|
191
|
+
type: "ref $module.Subscription",
|
|
192
|
+
optional: true,
|
|
193
|
+
},
|
|
194
|
+
{ name: "status", type: "text" },
|
|
195
|
+
],
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
name: "Entitlement",
|
|
199
|
+
ownership: "derived",
|
|
200
|
+
purpose: "Materialize product access from reconciled subscription state",
|
|
201
|
+
fields: [
|
|
202
|
+
{ name: "billing_account", type: "ref BillingAccount" },
|
|
203
|
+
{ name: "key", type: "text" },
|
|
204
|
+
{ name: "active", type: "boolean" },
|
|
205
|
+
],
|
|
206
|
+
},
|
|
207
|
+
],
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
reconciliation: [
|
|
211
|
+
{
|
|
212
|
+
event: "stripe.subscription.updated",
|
|
213
|
+
workflow: "ReconcileSubscription",
|
|
214
|
+
reads: ["stripe.Subscription", "BillingAccount"],
|
|
215
|
+
writes: ["BillingAccount", "Entitlement"],
|
|
216
|
+
outcome: "Subscription changes become application entitlements",
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
event: "stripe.invoice.payment_failed",
|
|
220
|
+
workflow: "ReconcileFailedPayment",
|
|
221
|
+
reads: ["stripe.Invoice", "BillingAccount"],
|
|
222
|
+
writes: ["BillingAccount", "Entitlement"],
|
|
223
|
+
outcome: "Failed payment state restricts derived entitlements",
|
|
224
|
+
},
|
|
225
|
+
],
|
|
226
|
+
placement: {
|
|
227
|
+
owner_claim: "billing.owner",
|
|
228
|
+
primary_application_model: "BillingAccount",
|
|
229
|
+
owner_field: "owner",
|
|
230
|
+
},
|
|
231
|
+
source_artifacts: [
|
|
232
|
+
{
|
|
233
|
+
path: "src/integrations/stripe/domain.ts",
|
|
234
|
+
role: "module-domain",
|
|
235
|
+
purpose: "Application billing state",
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
path: "src/integrations/stripe/provider-boundary.ts",
|
|
239
|
+
role: "module-provider-boundary",
|
|
240
|
+
purpose: "Stripe operations and verified event boundary",
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
path: "src/integrations/stripe/reconcile.ts",
|
|
244
|
+
role: "module-reconciliation",
|
|
245
|
+
purpose: "Subscription to entitlement reconciliation",
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
path: "src/integrations/stripe/IntegrationView.tsx",
|
|
249
|
+
role: "module-ui",
|
|
250
|
+
purpose: "Billing application experience",
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
path: "src/integrations/stripe/module.test.ts",
|
|
254
|
+
role: "module-contract-test",
|
|
255
|
+
purpose: "Module contract test",
|
|
256
|
+
},
|
|
257
|
+
],
|
|
258
|
+
};
|
|
259
|
+
const github = {
|
|
260
|
+
id: "github",
|
|
261
|
+
name: "GitHub App collaboration",
|
|
262
|
+
version: "1.0.0",
|
|
263
|
+
provider: "github-app",
|
|
264
|
+
compatibility: ["github", "github-app"],
|
|
265
|
+
intent_keywords: ["github", "repository", "repositories", "issues"],
|
|
266
|
+
models: [
|
|
267
|
+
model("Organization"),
|
|
268
|
+
model("Repository"),
|
|
269
|
+
model("Installation", "synchronized"),
|
|
270
|
+
model("Issue"),
|
|
271
|
+
model("Membership"),
|
|
272
|
+
],
|
|
273
|
+
relationships: [
|
|
274
|
+
{ from: "Organization", to: "Repository", kind: "many" },
|
|
275
|
+
{ from: "Installation", to: "Repository", kind: "many" },
|
|
276
|
+
{ from: "Repository", to: "Issue", kind: "many" },
|
|
277
|
+
],
|
|
278
|
+
events: [
|
|
279
|
+
"github.repository.created",
|
|
280
|
+
"github.repository.updated",
|
|
281
|
+
"github.repository.deleted",
|
|
282
|
+
"github.installation.created",
|
|
283
|
+
"github.installation.deleted",
|
|
284
|
+
"github.membership.added",
|
|
285
|
+
"github.membership.removed",
|
|
286
|
+
],
|
|
287
|
+
capabilities: [
|
|
288
|
+
"github.repository.read",
|
|
289
|
+
"github.repository.create",
|
|
290
|
+
"github.issue.read",
|
|
291
|
+
"github.issue.write",
|
|
292
|
+
"github.webhooks.receive",
|
|
293
|
+
],
|
|
294
|
+
workflows: ["SynchronizeRepository", "SynchronizeInstallation"],
|
|
295
|
+
configuration: [
|
|
296
|
+
{
|
|
297
|
+
name: "GITHUB_APP_ID",
|
|
298
|
+
required: true,
|
|
299
|
+
description: "GitHub App identifier",
|
|
300
|
+
visibility: "server",
|
|
301
|
+
},
|
|
302
|
+
],
|
|
303
|
+
secrets: [
|
|
304
|
+
{
|
|
305
|
+
name: "GITHUB_PRIVATE_KEY",
|
|
306
|
+
required: true,
|
|
307
|
+
description: "GitHub App signing key",
|
|
308
|
+
visibility: "server",
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
name: "GITHUB_WEBHOOK_SECRET",
|
|
312
|
+
required: true,
|
|
313
|
+
description: "GitHub webhook verification secret",
|
|
314
|
+
visibility: "server",
|
|
315
|
+
},
|
|
316
|
+
],
|
|
317
|
+
validation: [
|
|
318
|
+
"Webhook receivers must verify signatures",
|
|
319
|
+
"Repository writes require explicit application authorization",
|
|
320
|
+
],
|
|
321
|
+
dependencies: [
|
|
322
|
+
{
|
|
323
|
+
name: "authentication",
|
|
324
|
+
description: "GitHub installation management requires authenticated identity",
|
|
325
|
+
any_collections: ["User", "Account"],
|
|
326
|
+
any_capabilities: ["auth.session.read", "authentication"],
|
|
327
|
+
},
|
|
328
|
+
],
|
|
329
|
+
authorization: [
|
|
330
|
+
{
|
|
331
|
+
capability: "github.repository.read",
|
|
332
|
+
subject: "authenticated",
|
|
333
|
+
implication: "Authenticated members may read connected repositories",
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
capability: "github.repository.create",
|
|
337
|
+
subject: "owner",
|
|
338
|
+
implication: "The integration owner controls repository creation",
|
|
339
|
+
},
|
|
340
|
+
],
|
|
341
|
+
patterns: [
|
|
342
|
+
{
|
|
343
|
+
name: "organizational collaboration",
|
|
344
|
+
when: "Projects belong to an organization or workspace",
|
|
345
|
+
owner_candidates: ["Organization", "Workspace"],
|
|
346
|
+
application_models: [
|
|
347
|
+
{
|
|
348
|
+
name: "GitHubConnection",
|
|
349
|
+
ownership: "application-authoritative",
|
|
350
|
+
purpose: "Bind an application owner to a GitHub App installation",
|
|
351
|
+
fields: [
|
|
352
|
+
{ name: "owner", type: "ref $owner" },
|
|
353
|
+
{ name: "installation", type: "ref $module.Installation" },
|
|
354
|
+
{ name: "status", type: "text" },
|
|
355
|
+
],
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
name: "RepositoryConnection",
|
|
359
|
+
ownership: "synchronized",
|
|
360
|
+
purpose: "Map provider repositories into application projects",
|
|
361
|
+
fields: [
|
|
362
|
+
{ name: "connection", type: "ref GitHubConnection" },
|
|
363
|
+
{ name: "repository", type: "ref $module.Repository" },
|
|
364
|
+
{ name: "project", type: "ref $project", optional: true },
|
|
365
|
+
{ name: "synchronized_at", type: "datetime" },
|
|
366
|
+
],
|
|
367
|
+
},
|
|
368
|
+
],
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
name: "personal collaboration",
|
|
372
|
+
when: "Projects belong directly to a user",
|
|
373
|
+
owner_candidates: ["User", "Account"],
|
|
374
|
+
application_models: [
|
|
375
|
+
{
|
|
376
|
+
name: "GitHubConnection",
|
|
377
|
+
ownership: "application-authoritative",
|
|
378
|
+
purpose: "Bind a user to a GitHub App installation",
|
|
379
|
+
fields: [
|
|
380
|
+
{ name: "owner", type: "ref $owner" },
|
|
381
|
+
{ name: "installation", type: "ref $module.Installation" },
|
|
382
|
+
{ name: "status", type: "text" },
|
|
383
|
+
],
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
name: "RepositoryConnection",
|
|
387
|
+
ownership: "synchronized",
|
|
388
|
+
purpose: "Map provider repositories into application projects",
|
|
389
|
+
fields: [
|
|
390
|
+
{ name: "connection", type: "ref GitHubConnection" },
|
|
391
|
+
{ name: "repository", type: "ref $module.Repository" },
|
|
392
|
+
{ name: "project", type: "ref $project", optional: true },
|
|
393
|
+
{ name: "synchronized_at", type: "datetime" },
|
|
394
|
+
],
|
|
395
|
+
},
|
|
396
|
+
],
|
|
397
|
+
},
|
|
398
|
+
],
|
|
399
|
+
reconciliation: [
|
|
400
|
+
{
|
|
401
|
+
event: "github.repository.updated",
|
|
402
|
+
workflow: "SynchronizeRepository",
|
|
403
|
+
reads: ["github.Repository", "RepositoryConnection"],
|
|
404
|
+
writes: ["RepositoryConnection"],
|
|
405
|
+
outcome: "Repository changes synchronize into application project state",
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
event: "github.installation.created",
|
|
409
|
+
workflow: "SynchronizeInstallation",
|
|
410
|
+
reads: ["github.Installation"],
|
|
411
|
+
writes: ["GitHubConnection"],
|
|
412
|
+
outcome: "GitHub App installations become application connections",
|
|
413
|
+
},
|
|
414
|
+
],
|
|
415
|
+
placement: {
|
|
416
|
+
owner_claim: "repository.owner",
|
|
417
|
+
primary_application_model: "GitHubConnection",
|
|
418
|
+
owner_field: "owner",
|
|
419
|
+
},
|
|
420
|
+
source_artifacts: [
|
|
421
|
+
{
|
|
422
|
+
path: "src/integrations/github/domain.ts",
|
|
423
|
+
role: "module-domain",
|
|
424
|
+
purpose: "GitHub connection state",
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
path: "src/integrations/github/provider-boundary.ts",
|
|
428
|
+
role: "module-provider-boundary",
|
|
429
|
+
purpose: "GitHub App operations and webhook verification",
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
path: "src/integrations/github/reconcile.ts",
|
|
433
|
+
role: "module-reconciliation",
|
|
434
|
+
purpose: "Repository synchronization",
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
path: "src/integrations/github/IntegrationView.tsx",
|
|
438
|
+
role: "module-ui",
|
|
439
|
+
purpose: "Repository connection experience",
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
path: "src/integrations/github/module.test.ts",
|
|
443
|
+
role: "module-contract-test",
|
|
444
|
+
purpose: "Module contract test",
|
|
445
|
+
},
|
|
446
|
+
],
|
|
447
|
+
};
|
|
448
|
+
const definitions = new Map();
|
|
449
|
+
export function validateFeltDBModule(module) {
|
|
450
|
+
const errors = [];
|
|
451
|
+
for (const key of ["id", "name", "version", "provider"])
|
|
452
|
+
if (!module[key])
|
|
453
|
+
errors.push(`missing:${key}`);
|
|
454
|
+
for (const name of [
|
|
455
|
+
"compatibility",
|
|
456
|
+
"models",
|
|
457
|
+
"relationships",
|
|
458
|
+
"events",
|
|
459
|
+
"workflows",
|
|
460
|
+
"capabilities",
|
|
461
|
+
"configuration",
|
|
462
|
+
"secrets",
|
|
463
|
+
"authorization",
|
|
464
|
+
"dependencies",
|
|
465
|
+
"patterns",
|
|
466
|
+
"reconciliation",
|
|
467
|
+
"source_artifacts",
|
|
468
|
+
])
|
|
469
|
+
if (!Array.isArray(module[name]))
|
|
470
|
+
errors.push(`missing:${name}`);
|
|
471
|
+
for (const item of module.models ?? [])
|
|
472
|
+
if (![
|
|
473
|
+
"external-authoritative",
|
|
474
|
+
"application-authoritative",
|
|
475
|
+
"derived",
|
|
476
|
+
"synchronized",
|
|
477
|
+
].includes(item.ownership))
|
|
478
|
+
errors.push(`invalid_ownership:${item.name}`);
|
|
479
|
+
if (!module.placement?.owner_claim ||
|
|
480
|
+
!module.placement?.primary_application_model ||
|
|
481
|
+
!module.placement?.owner_field)
|
|
482
|
+
errors.push("missing:placement");
|
|
483
|
+
for (const pattern of module.patterns ?? [])
|
|
484
|
+
for (const applicationModel of pattern.application_models)
|
|
485
|
+
if (!applicationModel.fields?.length)
|
|
486
|
+
errors.push(`missing_fields:${applicationModel.name}`);
|
|
487
|
+
const modelNames = new Set((module.models ?? []).map(value => value.name));
|
|
488
|
+
for (const relationship of module.relationships ?? []) {
|
|
489
|
+
if (!modelNames.has(relationship.from))
|
|
490
|
+
errors.push(`unknown_relationship_model:${relationship.from}`);
|
|
491
|
+
if (!modelNames.has(relationship.to))
|
|
492
|
+
errors.push(`unknown_relationship_model:${relationship.to}`);
|
|
493
|
+
}
|
|
494
|
+
const events = new Set(module.events ?? []);
|
|
495
|
+
const workflows = new Set(module.workflows ?? []);
|
|
496
|
+
const capabilities = new Set(module.capabilities ?? []);
|
|
497
|
+
for (const reconciliation of module.reconciliation ?? []) {
|
|
498
|
+
if (!events.has(reconciliation.event))
|
|
499
|
+
errors.push(`undeclared_reconciliation_event:${reconciliation.event}`);
|
|
500
|
+
if (!workflows.has(reconciliation.workflow))
|
|
501
|
+
errors.push(`undeclared_reconciliation_workflow:${reconciliation.workflow}`);
|
|
502
|
+
}
|
|
503
|
+
for (const authorization of module.authorization ?? [])
|
|
504
|
+
if (!capabilities.has(authorization.capability))
|
|
505
|
+
errors.push(`undeclared_authorization_capability:${authorization.capability}`);
|
|
506
|
+
for (const secret of module.secrets ?? [])
|
|
507
|
+
if (secret.visibility === 'browser' || secret.name.startsWith('VITE_'))
|
|
508
|
+
errors.push(`browser_secret:${secret.name}`);
|
|
509
|
+
const sourceRoles = new Set(['module-domain', 'module-provider-boundary', 'module-reconciliation', 'module-ui', 'module-contract-test']);
|
|
510
|
+
for (const artifact of module.source_artifacts ?? [])
|
|
511
|
+
if (!artifact.path.startsWith(`src/integrations/${module.id}/`) || !sourceRoles.has(artifact.role))
|
|
512
|
+
errors.push(`invalid_source_artifact:${artifact.path}`);
|
|
513
|
+
return [...new Set(errors)];
|
|
514
|
+
}
|
|
515
|
+
export function registerFeltDBModule(module) {
|
|
516
|
+
const errors = validateFeltDBModule(module);
|
|
517
|
+
if (errors.length)
|
|
518
|
+
throw new Error(`MODULE_CONFORMANCE_FAILED: ${errors.join(", ")}`);
|
|
519
|
+
if (definitions.has(module.id))
|
|
520
|
+
throw new Error(`MODULE_ALREADY_REGISTERED: ${module.id}`);
|
|
521
|
+
definitions.set(module.id, structuredClone(module));
|
|
522
|
+
return () => {
|
|
523
|
+
definitions.delete(module.id);
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
registerFeltDBModule(stripe);
|
|
527
|
+
registerFeltDBModule(github);
|
|
528
|
+
export function listFeltDBModules() {
|
|
529
|
+
return [...definitions.values()]
|
|
530
|
+
.map((value) => structuredClone(value))
|
|
531
|
+
.sort((a, b) => a.id.localeCompare(b.id));
|
|
532
|
+
}
|
|
533
|
+
export function resolveFeltDBModule(declaration) {
|
|
534
|
+
const definition = definitions.get(declaration.name);
|
|
535
|
+
if (!definition)
|
|
536
|
+
throw new Error(`UNKNOWN_MODULE: ${declaration.name}`);
|
|
537
|
+
if (!definition.compatibility.includes(declaration.provider))
|
|
538
|
+
throw new Error(`INCOMPATIBLE_MODULE_PROVIDER: ${declaration.name} does not support ${declaration.provider}`);
|
|
539
|
+
if (declaration.version && declaration.version !== definition.version)
|
|
540
|
+
throw new Error(`INCOMPATIBLE_MODULE_VERSION: ${declaration.name}@${declaration.version}; available ${definition.version}`);
|
|
541
|
+
return { ...structuredClone(definition), provider: declaration.provider };
|
|
542
|
+
}
|
|
543
|
+
export function findFeltDBModules(query) {
|
|
544
|
+
const normalized = query.trim().toLowerCase();
|
|
545
|
+
return listFeltDBModules().filter((module) => module.id === normalized ||
|
|
546
|
+
module.name.toLowerCase().includes(normalized) ||
|
|
547
|
+
module.compatibility.some((value) => value.includes(normalized)) ||
|
|
548
|
+
module.intent_keywords.includes(normalized));
|
|
549
|
+
}
|
|
550
|
+
export function resolveFeltDBModules(declarations = []) {
|
|
551
|
+
return declarations
|
|
552
|
+
.map(resolveFeltDBModule)
|
|
553
|
+
.sort((a, b) => a.id.localeCompare(b.id));
|
|
554
|
+
}
|
|
555
|
+
export function validateResolvedModules(modules, environment = "development") {
|
|
556
|
+
return modules.flatMap((module) => [
|
|
557
|
+
...validateFeltDBModule(module).map((value) => `${module.id}: ${value}`),
|
|
558
|
+
...module.secrets
|
|
559
|
+
.filter((value) => value.required &&
|
|
560
|
+
(!value.environments || value.environments.includes(environment)))
|
|
561
|
+
.map((value) => `${value.name} is required in ${environment} runtime configuration`),
|
|
562
|
+
...module.capabilities
|
|
563
|
+
.filter((value) => value.endsWith(".create"))
|
|
564
|
+
.map((value) => `${value} requires an explicit authorization policy`),
|
|
565
|
+
]);
|
|
566
|
+
}
|