@fungi.computer/puffball 0.0.0-stage → 0.0.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/LICENSE +21 -0
- package/README.md +443 -2
- package/dist/app-api.d.ts +7 -0
- package/dist/app-api.js +61 -0
- package/dist/app-backend-binding-vocabulary.d.ts +299 -0
- package/dist/app-backend-binding-vocabulary.js +257 -0
- package/dist/app-backend-bindings.d.ts +21 -0
- package/dist/app-backend-bindings.js +47 -0
- package/dist/app-declaration.d.ts +46 -0
- package/dist/app-declaration.js +115 -0
- package/dist/app-event-facts.d.ts +40 -0
- package/dist/app-event-facts.js +28 -0
- package/dist/app-method-context.d.ts +109 -0
- package/dist/app-method-context.js +9 -0
- package/dist/app-method-runtime.d.ts +86 -0
- package/dist/app-method-runtime.js +122 -0
- package/dist/app-origin-paths.d.ts +6 -0
- package/dist/app-origin-paths.js +6 -0
- package/dist/app-vocabulary.d.ts +189 -0
- package/dist/app-vocabulary.js +103 -0
- package/dist/app.d.ts +379 -0
- package/dist/app.js +71 -0
- package/dist/artifact-dispositions.d.ts +115 -0
- package/dist/artifact-dispositions.js +234 -0
- package/dist/assets.d.ts +54 -0
- package/dist/assets.js +89 -0
- package/dist/backend.d.ts +41 -0
- package/dist/backend.js +29 -0
- package/dist/background-replay.d.ts +115 -0
- package/dist/background-replay.js +175 -0
- package/dist/buyer-references.d.ts +69 -0
- package/dist/buyer-references.js +154 -0
- package/dist/cloudflare-assets.d.ts +48 -0
- package/dist/cloudflare-assets.js +105 -0
- package/dist/cloudflare.d.ts +254 -0
- package/dist/cloudflare.js +1619 -0
- package/dist/effect.d.ts +73 -0
- package/dist/effect.js +325 -0
- package/dist/git-representation.d.ts +13 -0
- package/dist/git-representation.js +16 -0
- package/dist/inbox.d.ts +132 -0
- package/dist/inbox.js +81 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +85 -0
- package/dist/internal/app-description.d.ts +14 -0
- package/dist/internal/app-description.js +98 -0
- package/dist/internal/app-release-artifact-reader.d.ts +26 -0
- package/dist/internal/app-release-artifact-reader.js +1 -0
- package/dist/internal/app-release-contract.d.ts +540 -0
- package/dist/internal/app-release-contract.js +169 -0
- package/dist/internal/app-release-schema.d.ts +1676 -0
- package/dist/internal/app-release-schema.js +386 -0
- package/dist/internal/app-release-store.d.ts +47 -0
- package/dist/internal/app-release-store.js +1 -0
- package/dist/internal/background-sync.d.ts +7 -0
- package/dist/internal/background-sync.js +10 -0
- package/dist/internal/deterministic-memory-app-release-store.d.ts +14 -0
- package/dist/internal/deterministic-memory-app-release-store.js +319 -0
- package/dist/internal/failure.d.ts +2 -0
- package/dist/internal/failure.js +9 -0
- package/dist/internal/immutable-release-material.d.ts +3 -0
- package/dist/internal/immutable-release-material.js +13 -0
- package/dist/internal/promise-app-release-store-adapter.d.ts +9 -0
- package/dist/internal/promise-app-release-store-adapter.js +65 -0
- package/dist/internal/promise-artifact-reader-adapter.d.ts +9 -0
- package/dist/internal/promise-artifact-reader-adapter.js +18 -0
- package/dist/internal/public-route-sql.d.ts +10 -0
- package/dist/internal/public-route-sql.js +239 -0
- package/dist/internal/public-website-authority.d.ts +338 -0
- package/dist/internal/public-website-authority.js +50 -0
- package/dist/internal/public-website-delivery.d.ts +59 -0
- package/dist/internal/public-website-delivery.js +232 -0
- package/dist/internal/public-website-fetch.d.ts +8 -0
- package/dist/internal/public-website-fetch.js +54 -0
- package/dist/internal/release-transition-material.d.ts +3 -0
- package/dist/internal/release-transition-material.js +11 -0
- package/dist/internal/verified-artifact-snapshot.d.ts +41 -0
- package/dist/internal/verified-artifact-snapshot.js +91 -0
- package/dist/public-route-moderation.d.ts +83 -0
- package/dist/public-route-moderation.js +236 -0
- package/dist/public-route-policy.d.ts +51 -0
- package/dist/public-route-policy.js +88 -0
- package/dist/public-routes.d.ts +34 -0
- package/dist/public-routes.js +136 -0
- package/dist/publisher.d.ts +61 -0
- package/dist/publisher.js +16 -0
- package/dist/safety-takedown.d.ts +56 -0
- package/dist/safety-takedown.js +146 -0
- package/dist/seller-closure-notice.d.ts +14 -0
- package/dist/seller-closure-notice.js +14 -0
- package/dist/seller-closure.d.ts +15 -0
- package/dist/seller-closure.js +31 -0
- package/dist/testing.d.ts +8 -0
- package/dist/testing.js +47 -0
- package/docs/api/README.md +26 -0
- package/docs/api/app-backend-binding-vocabulary.md +276 -0
- package/docs/api/app-backend-bindings.md +141 -0
- package/docs/api/app-event-facts.md +110 -0
- package/docs/api/app-method-context.md +166 -0
- package/docs/api/app-method-runtime.md +330 -0
- package/docs/api/backend.md +108 -0
- package/docs/api/background-replay.md +516 -0
- package/docs/api/cloudflare.md +1044 -0
- package/docs/api/effect.md +2429 -0
- package/docs/api/git-representation.md +56 -0
- package/docs/api/inbox.md +289 -0
- package/docs/api/index.md +2868 -0
- package/docs/api/publisher.md +147 -0
- package/docs/api/testing.md +31 -0
- package/package.json +158 -3
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Schema from "effect/Schema";
|
|
3
|
+
import { appDeclarationSchema } from "../app-declaration.js";
|
|
4
|
+
import { emptyAppDeclaration } from "../app-vocabulary.js";
|
|
5
|
+
import { defineIdFamily } from "@fungi.computer/cairn/id";
|
|
6
|
+
function isAppId(input) {
|
|
7
|
+
return /^app_[a-z0-9]{1,63}$/u.test(input);
|
|
8
|
+
}
|
|
9
|
+
function isReleaseId(input) {
|
|
10
|
+
return /^rel_[a-z0-9]{1,63}$/u.test(input);
|
|
11
|
+
}
|
|
12
|
+
function isPublicSurfaceId(input) {
|
|
13
|
+
return /^ps_[a-z0-9]{1,63}$/u.test(input);
|
|
14
|
+
}
|
|
15
|
+
function isArtifactRef(input) {
|
|
16
|
+
return /^artifact:[a-z0-9](?:[a-z0-9._-]{0,126}[a-z0-9])?$/u.test(input);
|
|
17
|
+
}
|
|
18
|
+
function isIdempotencyKey(input) {
|
|
19
|
+
return /^idem_[a-z0-9](?:[a-z0-9_-]{0,126}[a-z0-9])?$/u.test(input);
|
|
20
|
+
}
|
|
21
|
+
function isSourceRevision(input) {
|
|
22
|
+
return /^git:[0-9a-f]{40}$/u.test(input);
|
|
23
|
+
}
|
|
24
|
+
function isSha256Digest(input) {
|
|
25
|
+
return /^sha256:[0-9a-f]{64}$/u.test(input);
|
|
26
|
+
}
|
|
27
|
+
function isStableRoute(input) {
|
|
28
|
+
return /^\/[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/u.test(input);
|
|
29
|
+
}
|
|
30
|
+
const appReleaseIdFamily = defineIdFamily({
|
|
31
|
+
family: "app-release",
|
|
32
|
+
version: 1,
|
|
33
|
+
kinds: {
|
|
34
|
+
transition: { prefix: "app_transition" },
|
|
35
|
+
surface: { prefix: "ps" },
|
|
36
|
+
erasure: { prefix: "app_erasure" },
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
/** Cairn owns the App transition identity grammar and parser. */
|
|
40
|
+
export const appTransitionIdCodec = appReleaseIdFamily.transition;
|
|
41
|
+
export const appSurfaceIdCodec = appReleaseIdFamily.surface;
|
|
42
|
+
export const appErasureIdCodec = appReleaseIdFamily.erasure;
|
|
43
|
+
/** Canonical Effect Schema for one Global App identifier. */
|
|
44
|
+
export const appIdSchema = Schema.String.pipe(Schema.refine(isAppId));
|
|
45
|
+
/** Canonical Effect Schema for one immutable Release identifier. */
|
|
46
|
+
export const releaseIdSchema = Schema.String.pipe(Schema.refine(isReleaseId));
|
|
47
|
+
/** Canonical Effect Schema for one anonymous public-Surface identifier. */
|
|
48
|
+
export const publicSurfaceIdSchema = Schema.String.pipe(Schema.refine(isPublicSurfaceId));
|
|
49
|
+
/** Canonical Effect Schema for one bounded artifact reference. */
|
|
50
|
+
export const artifactRefSchema = Schema.String.pipe(Schema.refine(isArtifactRef));
|
|
51
|
+
/** Canonical Effect Schema for one caller-provided idempotency key. */
|
|
52
|
+
export const idempotencyKeySchema = Schema.String.pipe(Schema.refine(isIdempotencyKey));
|
|
53
|
+
/** Canonical Effect Schema for one pinned lowercase Git source revision. */
|
|
54
|
+
export const sourceRevisionSchema = Schema.String.pipe(Schema.refine(isSourceRevision));
|
|
55
|
+
/** Canonical Effect Schema for one lowercase SHA-256 digest. */
|
|
56
|
+
export const sha256DigestSchema = Schema.String.pipe(Schema.refine(isSha256Digest));
|
|
57
|
+
/** Canonical Effect Schema for one canonical local stable route. */
|
|
58
|
+
export const stableRouteSchema = Schema.String.pipe(Schema.refine(isStableRoute));
|
|
59
|
+
const immutableArtifactBytesSchema = Schema.Struct({
|
|
60
|
+
byteLength: Schema.Number,
|
|
61
|
+
copy: Schema.instanceOf(Function),
|
|
62
|
+
}).pipe(Schema.refine((input) => input.byteLength >= 0));
|
|
63
|
+
/** Canonical Effect Schema for a Global App record. */
|
|
64
|
+
export const appSchema = Schema.Struct({ appId: appIdSchema });
|
|
65
|
+
/** Canonical Effect Schema for immutable source and build provenance. */
|
|
66
|
+
export const artifactProvenanceSchema = Schema.Struct({
|
|
67
|
+
sourceRevision: sourceRevisionSchema,
|
|
68
|
+
sourceTreeDigest: sha256DigestSchema,
|
|
69
|
+
buildRecipeDigest: sha256DigestSchema,
|
|
70
|
+
});
|
|
71
|
+
/** Canonical Effect Schema for immutable artifact identity and provenance. */
|
|
72
|
+
export const releaseArtifactSchema = Schema.Struct({
|
|
73
|
+
artifactRef: artifactRefSchema,
|
|
74
|
+
artifactDigest: sha256DigestSchema,
|
|
75
|
+
provenance: artifactProvenanceSchema,
|
|
76
|
+
});
|
|
77
|
+
/** Canonical Effect Schema for one immutable App Release. */
|
|
78
|
+
export const releaseSchema = Schema.Struct({
|
|
79
|
+
releaseId: releaseIdSchema,
|
|
80
|
+
appId: appIdSchema,
|
|
81
|
+
artifact: releaseArtifactSchema,
|
|
82
|
+
});
|
|
83
|
+
/** Canonical Effect Schema for one App-owned anonymous public Surface. */
|
|
84
|
+
export const publicSurfaceSchema = Schema.Struct({
|
|
85
|
+
publicSurfaceId: publicSurfaceIdSchema,
|
|
86
|
+
appId: appIdSchema,
|
|
87
|
+
stableRoute: stableRouteSchema,
|
|
88
|
+
});
|
|
89
|
+
const publicationIdentitySchema = Schema.String.pipe(Schema.check(Schema.isMinLength(1)), Schema.check(Schema.isMaxLength(256)));
|
|
90
|
+
const publicSurfaceDefinitionSchema = Schema.Struct({
|
|
91
|
+
...publicSurfaceSchema.fields,
|
|
92
|
+
publisher: Schema.Struct({
|
|
93
|
+
kind: Schema.Literals(["customer", "platform"]),
|
|
94
|
+
teamId: publicationIdentitySchema,
|
|
95
|
+
userId: publicationIdentitySchema,
|
|
96
|
+
requestKey: publicationIdentitySchema,
|
|
97
|
+
}),
|
|
98
|
+
});
|
|
99
|
+
/** Supported immutable artifact representation formats at the storage boundary. */
|
|
100
|
+
export const artifactMediaTypeSchema = Schema.Literals([
|
|
101
|
+
"text/html; charset=utf-8",
|
|
102
|
+
"application/vnd.fungi.app-backend+json",
|
|
103
|
+
"application/vnd.fungi.app-assets+json",
|
|
104
|
+
"application/vnd.fungi.app+json",
|
|
105
|
+
]);
|
|
106
|
+
const verifiedAppArtifactReferenceSchema = Schema.Struct({
|
|
107
|
+
artifactRef: artifactRefSchema,
|
|
108
|
+
digest: sha256DigestSchema,
|
|
109
|
+
mediaType: Schema.Literals([
|
|
110
|
+
"text/html; charset=utf-8",
|
|
111
|
+
"application/vnd.fungi.app-backend+json",
|
|
112
|
+
"application/vnd.fungi.app-assets+json",
|
|
113
|
+
]),
|
|
114
|
+
version: Schema.String.pipe(Schema.check(Schema.isMinLength(1))),
|
|
115
|
+
byteLength: Schema.Number.pipe(Schema.check(Schema.isInt()), Schema.check(Schema.isGreaterThan(0)), Schema.check(Schema.makeFilter(Number.isSafeInteger))),
|
|
116
|
+
});
|
|
117
|
+
const verifiedBackendProfileSchema = Schema.Struct({
|
|
118
|
+
runtime: Schema.Struct({
|
|
119
|
+
kind: Schema.Literal("durable-facet"),
|
|
120
|
+
stateSchema: Schema.Number.pipe(Schema.check(Schema.isInt()), Schema.check(Schema.isGreaterThan(0))),
|
|
121
|
+
}),
|
|
122
|
+
compatibilityDate: Schema.String.pipe(Schema.check(Schema.isPattern(/^\d{4}-\d{2}-\d{2}$/))),
|
|
123
|
+
exportName: Schema.String.pipe(Schema.check(Schema.isMinLength(1))),
|
|
124
|
+
});
|
|
125
|
+
/** Canonical persisted metadata derived only by App artifact verification. */
|
|
126
|
+
export const verifiedAppDescriptionSchema = Schema.Struct({
|
|
127
|
+
format: Schema.Literal("fungi-app-v1"),
|
|
128
|
+
ui: Schema.NullOr(verifiedAppArtifactReferenceSchema),
|
|
129
|
+
backend: Schema.NullOr(Schema.Struct({
|
|
130
|
+
artifact: verifiedAppArtifactReferenceSchema,
|
|
131
|
+
profile: verifiedBackendProfileSchema,
|
|
132
|
+
})),
|
|
133
|
+
// Metadata verified before declarations existed requested nothing.
|
|
134
|
+
declaration: appDeclarationSchema.pipe(Schema.withDecodingDefaultType(Effect.succeed(emptyAppDeclaration))),
|
|
135
|
+
});
|
|
136
|
+
/** Canonical Effect Schema for a verified immutable artifact snapshot. */
|
|
137
|
+
export const verifiedArtifactReadSchema = Schema.Struct({
|
|
138
|
+
kind: Schema.Literal("verified"),
|
|
139
|
+
digest: sha256DigestSchema,
|
|
140
|
+
mediaType: artifactMediaTypeSchema,
|
|
141
|
+
bytes: immutableArtifactBytesSchema,
|
|
142
|
+
byteLength: Schema.Number,
|
|
143
|
+
});
|
|
144
|
+
/** Canonical Effect Schema for the complete hostile artifact-reader result. */
|
|
145
|
+
export const artifactReadResultSchema = Schema.Union([
|
|
146
|
+
verifiedArtifactReadSchema,
|
|
147
|
+
Schema.Struct({ kind: Schema.Literal("unavailable") }),
|
|
148
|
+
Schema.Struct({ kind: Schema.Literal("missing") }),
|
|
149
|
+
Schema.Struct({
|
|
150
|
+
kind: Schema.Literal("digest-mismatch"),
|
|
151
|
+
actualDigest: sha256DigestSchema,
|
|
152
|
+
}),
|
|
153
|
+
]);
|
|
154
|
+
/** Canonical Effect Schema for one explicit App lookup result. */
|
|
155
|
+
export const appReadSchema = Schema.Union([
|
|
156
|
+
Schema.Struct({ kind: Schema.Literal("found"), app: appSchema }),
|
|
157
|
+
Schema.Struct({ kind: Schema.Literal("absent") }),
|
|
158
|
+
]);
|
|
159
|
+
/** Canonical Effect Schema for one explicit App create-or-observe result. */
|
|
160
|
+
export const appCreateSchema = Schema.Union([
|
|
161
|
+
Schema.Struct({ kind: Schema.Literal("created"), app: appSchema }),
|
|
162
|
+
Schema.Struct({ kind: Schema.Literal("existing"), app: appSchema }),
|
|
163
|
+
]);
|
|
164
|
+
/** Canonical Effect Schema for one explicit Release lookup result. */
|
|
165
|
+
export const releaseReadSchema = Schema.Union([
|
|
166
|
+
Schema.Struct({ kind: Schema.Literal("found"), release: releaseSchema }),
|
|
167
|
+
Schema.Struct({ kind: Schema.Literal("absent") }),
|
|
168
|
+
]);
|
|
169
|
+
/** Canonical Effect Schema for one explicit Release create-or-observe result. */
|
|
170
|
+
export const releaseCreateSchema = Schema.Union([
|
|
171
|
+
Schema.Struct({ kind: Schema.Literal("created"), release: releaseSchema }),
|
|
172
|
+
Schema.Struct({ kind: Schema.Literal("existing"), release: releaseSchema }),
|
|
173
|
+
]);
|
|
174
|
+
/** Canonical Effect Schema for one explicit public-Surface lookup result. */
|
|
175
|
+
export const publicSurfaceReadSchema = Schema.Union([
|
|
176
|
+
Schema.Struct({
|
|
177
|
+
kind: Schema.Literal("found"),
|
|
178
|
+
surface: publicSurfaceSchema,
|
|
179
|
+
}),
|
|
180
|
+
Schema.Struct({ kind: Schema.Literal("absent") }),
|
|
181
|
+
]);
|
|
182
|
+
/** Canonical Effect Schema for one public-Surface create-or-observe result. */
|
|
183
|
+
export const publicSurfaceCreateSchema = Schema.Union([
|
|
184
|
+
Schema.Struct({
|
|
185
|
+
kind: Schema.Literal("created"),
|
|
186
|
+
surface: publicSurfaceSchema,
|
|
187
|
+
}),
|
|
188
|
+
Schema.Struct({
|
|
189
|
+
kind: Schema.Literal("existing"),
|
|
190
|
+
surface: publicSurfaceSchema,
|
|
191
|
+
}),
|
|
192
|
+
Schema.Struct({ kind: Schema.Literal("conflict") }),
|
|
193
|
+
]);
|
|
194
|
+
/** Canonical Effect Schema for a verified/unverified Release fact. */
|
|
195
|
+
export const releaseVerificationSchema = Schema.Union([
|
|
196
|
+
Schema.Struct({
|
|
197
|
+
kind: Schema.Literal("verified"),
|
|
198
|
+
digest: sha256DigestSchema,
|
|
199
|
+
mediaType: Schema.Literal("application/vnd.fungi.app+json"),
|
|
200
|
+
description: verifiedAppDescriptionSchema,
|
|
201
|
+
}),
|
|
202
|
+
Schema.Struct({ kind: Schema.Literal("unverified") }),
|
|
203
|
+
]);
|
|
204
|
+
/** Canonical Effect Schema for a live/revoked Release fact. */
|
|
205
|
+
export const releaseRevocationSchema = Schema.Union([
|
|
206
|
+
Schema.Struct({ kind: Schema.Literal("active") }),
|
|
207
|
+
Schema.Struct({ kind: Schema.Literal("revoked") }),
|
|
208
|
+
]);
|
|
209
|
+
/** Canonical Effect Schema for one owner-issued transition command. */
|
|
210
|
+
export const releaseTransitionSchema = Schema.Union([
|
|
211
|
+
Schema.Struct({
|
|
212
|
+
kind: Schema.Literal("promotion"),
|
|
213
|
+
publicSurfaceId: publicSurfaceIdSchema,
|
|
214
|
+
releaseId: releaseIdSchema,
|
|
215
|
+
idempotencyKey: idempotencyKeySchema,
|
|
216
|
+
}),
|
|
217
|
+
Schema.Struct({
|
|
218
|
+
kind: Schema.Literal("rollback"),
|
|
219
|
+
publicSurfaceId: publicSurfaceIdSchema,
|
|
220
|
+
releaseId: releaseIdSchema,
|
|
221
|
+
idempotencyKey: idempotencyKeySchema,
|
|
222
|
+
}),
|
|
223
|
+
Schema.Struct({
|
|
224
|
+
kind: Schema.Literal("revocation"),
|
|
225
|
+
releaseId: releaseIdSchema,
|
|
226
|
+
idempotencyKey: idempotencyKeySchema,
|
|
227
|
+
}),
|
|
228
|
+
]);
|
|
229
|
+
/** The sole Effect Schema wrapper around Cairn's transition codec parser. */
|
|
230
|
+
export const appTransitionIdSchema = Schema.declare((input) => appTransitionIdCodec.schema.safeParse(input).success);
|
|
231
|
+
/** Canonical Effect Schema for a terminal owner-issued transition receipt. */
|
|
232
|
+
export const transitionReceiptSchema = Schema.Struct({
|
|
233
|
+
transition: releaseTransitionSchema,
|
|
234
|
+
transitionId: appTransitionIdSchema,
|
|
235
|
+
});
|
|
236
|
+
const releaseSelectionSchema = Schema.Union([
|
|
237
|
+
Schema.Struct({ kind: Schema.Literal("none") }),
|
|
238
|
+
Schema.Struct({
|
|
239
|
+
kind: Schema.Literal("selected"),
|
|
240
|
+
releaseId: releaseIdSchema,
|
|
241
|
+
}),
|
|
242
|
+
]);
|
|
243
|
+
/** Canonical Effect Schema for durable Release lifecycle facts. */
|
|
244
|
+
export const releaseLifecycleSchema = Schema.Union([
|
|
245
|
+
Schema.Struct({
|
|
246
|
+
kind: Schema.Literal("found"),
|
|
247
|
+
release: releaseSchema,
|
|
248
|
+
verification: releaseVerificationSchema,
|
|
249
|
+
revocation: releaseRevocationSchema,
|
|
250
|
+
}),
|
|
251
|
+
Schema.Struct({ kind: Schema.Literal("absent") }),
|
|
252
|
+
]);
|
|
253
|
+
/** Canonical Effect Schema for durable public-Surface selection facts. */
|
|
254
|
+
export const publicSurfaceLifecycleSchema = Schema.Union([
|
|
255
|
+
Schema.Struct({
|
|
256
|
+
kind: Schema.Literal("found"),
|
|
257
|
+
surface: publicSurfaceSchema,
|
|
258
|
+
selection: releaseSelectionSchema,
|
|
259
|
+
}),
|
|
260
|
+
Schema.Struct({ kind: Schema.Literal("absent") }),
|
|
261
|
+
]);
|
|
262
|
+
/** Canonical Effect Schema for an operation-scoped receipt lookup. */
|
|
263
|
+
export const transitionLookupSchema = Schema.Union([
|
|
264
|
+
Schema.Struct({ kind: Schema.Literal("absent") }),
|
|
265
|
+
Schema.Struct({
|
|
266
|
+
kind: Schema.Literal("found"),
|
|
267
|
+
receipt: transitionReceiptSchema,
|
|
268
|
+
}),
|
|
269
|
+
Schema.Struct({ kind: Schema.Literal("conflict") }),
|
|
270
|
+
]);
|
|
271
|
+
/** Canonical Effect Schema for atomic transition persistence. */
|
|
272
|
+
export const transitionPersistenceSchema = Schema.Union([
|
|
273
|
+
Schema.Struct({
|
|
274
|
+
kind: Schema.Literal("created"),
|
|
275
|
+
receipt: transitionReceiptSchema,
|
|
276
|
+
}),
|
|
277
|
+
Schema.Struct({
|
|
278
|
+
kind: Schema.Literal("existing"),
|
|
279
|
+
receipt: transitionReceiptSchema,
|
|
280
|
+
}),
|
|
281
|
+
Schema.Struct({ kind: Schema.Literal("conflict") }),
|
|
282
|
+
Schema.Struct({ kind: Schema.Literal("identity-collision") }),
|
|
283
|
+
Schema.Struct({ kind: Schema.Literal("lifecycle-conflict") }),
|
|
284
|
+
]);
|
|
285
|
+
/** Canonical Effect Schema for recording one verified Release artifact. */
|
|
286
|
+
const releaseVerificationRecordSchema = Schema.Struct({
|
|
287
|
+
kind: Schema.Literal("recorded"),
|
|
288
|
+
});
|
|
289
|
+
/** Canonical Effect Schema for a closed App Release store infrastructure failure. */
|
|
290
|
+
export const appReleaseStoreFailureSchema = Schema.Struct({
|
|
291
|
+
kind: Schema.Literal("unavailable"),
|
|
292
|
+
});
|
|
293
|
+
function storeResultSchema(value) {
|
|
294
|
+
return Schema.Union([
|
|
295
|
+
Schema.Struct({ kind: Schema.Literal("success"), value }),
|
|
296
|
+
Schema.Struct({
|
|
297
|
+
kind: Schema.Literal("failure"),
|
|
298
|
+
failure: appReleaseStoreFailureSchema,
|
|
299
|
+
}),
|
|
300
|
+
]);
|
|
301
|
+
}
|
|
302
|
+
/** Canonical Effect Schema for a closed App-read store result envelope. */
|
|
303
|
+
export const appReadStoreResultSchema = storeResultSchema(appReadSchema);
|
|
304
|
+
/** Canonical Effect Schema for a closed App-create store result envelope. */
|
|
305
|
+
export const appCreateStoreResultSchema = storeResultSchema(appCreateSchema);
|
|
306
|
+
/** Canonical Effect Schema for a closed Release-read store result envelope. */
|
|
307
|
+
export const releaseReadStoreResultSchema = storeResultSchema(releaseReadSchema);
|
|
308
|
+
/** Canonical Effect Schema for a closed Release-create store result envelope. */
|
|
309
|
+
export const releaseCreateStoreResultSchema = storeResultSchema(releaseCreateSchema);
|
|
310
|
+
/** Canonical Effect Schema for a closed public-Surface-read store result envelope. */
|
|
311
|
+
export const publicSurfaceReadStoreResultSchema = storeResultSchema(publicSurfaceReadSchema);
|
|
312
|
+
/** Canonical Effect Schema for a closed public-Surface-create store result envelope. */
|
|
313
|
+
export const publicSurfaceCreateStoreResultSchema = storeResultSchema(publicSurfaceCreateSchema);
|
|
314
|
+
/** Canonical Effect Schema for a Release lifecycle store result envelope. */
|
|
315
|
+
export const releaseLifecycleStoreResultSchema = storeResultSchema(releaseLifecycleSchema);
|
|
316
|
+
/** Canonical Effect Schema for a Release verification record result envelope. */
|
|
317
|
+
export const releaseVerificationRecordStoreResultSchema = storeResultSchema(releaseVerificationRecordSchema);
|
|
318
|
+
/** Canonical Effect Schema for a transition lookup store result envelope. */
|
|
319
|
+
export const transitionLookupStoreResultSchema = storeResultSchema(transitionLookupSchema);
|
|
320
|
+
/** Canonical Effect Schema for transition persistence store result envelope. */
|
|
321
|
+
export const transitionPersistenceStoreResultSchema = storeResultSchema(transitionPersistenceSchema);
|
|
322
|
+
/** Decode one Global App identifier through its canonical closed Effect Schema. */
|
|
323
|
+
export const decodeAppId = Schema.decodeUnknownResult(appIdSchema, {
|
|
324
|
+
onExcessProperty: "error",
|
|
325
|
+
});
|
|
326
|
+
/** Decode one immutable Release identifier through its canonical closed Effect Schema. */
|
|
327
|
+
export const decodeReleaseId = Schema.decodeUnknownResult(releaseIdSchema, {
|
|
328
|
+
onExcessProperty: "error",
|
|
329
|
+
});
|
|
330
|
+
/** Decode one public-Surface identifier through its canonical closed Effect Schema. */
|
|
331
|
+
export const decodePublicSurfaceId = Schema.decodeUnknownResult(publicSurfaceIdSchema, { onExcessProperty: "error" });
|
|
332
|
+
/** Decode one bounded artifact reference through its canonical closed Effect Schema. */
|
|
333
|
+
export const decodeArtifactRef = Schema.decodeUnknownResult(artifactRefSchema, {
|
|
334
|
+
onExcessProperty: "error",
|
|
335
|
+
});
|
|
336
|
+
/** Decode one idempotency key through its canonical closed Effect Schema. */
|
|
337
|
+
export const decodeIdempotencyKey = Schema.decodeUnknownResult(idempotencyKeySchema, { onExcessProperty: "error" });
|
|
338
|
+
/** Decode one pinned source revision through its canonical closed Effect Schema. */
|
|
339
|
+
export const decodeSourceRevision = Schema.decodeUnknownResult(sourceRevisionSchema, { onExcessProperty: "error" });
|
|
340
|
+
/** Decode one SHA-256 digest through its canonical closed Effect Schema. */
|
|
341
|
+
export const decodeSha256Digest = Schema.decodeUnknownResult(sha256DigestSchema, { onExcessProperty: "error" });
|
|
342
|
+
/** Decode one local stable route through its canonical closed Effect Schema. */
|
|
343
|
+
export const decodeStableRoute = Schema.decodeUnknownResult(stableRouteSchema, {
|
|
344
|
+
onExcessProperty: "error",
|
|
345
|
+
});
|
|
346
|
+
/** Decode a Cairn-issued App transition identity through its sole wrapper. */
|
|
347
|
+
export const decodeAppTransitionId = Schema.decodeUnknownResult(appTransitionIdSchema, { onExcessProperty: "error" });
|
|
348
|
+
/** Decode a hostile artifact-reader result through its canonical closed schema. */
|
|
349
|
+
export const decodeArtifactReadResult = Schema.decodeUnknownEffect(artifactReadResultSchema, { onExcessProperty: "error" });
|
|
350
|
+
/** Decode a hostile App record through its canonical closed schema. */
|
|
351
|
+
export const decodeApp = Schema.decodeUnknownResult(appSchema, {
|
|
352
|
+
onExcessProperty: "error",
|
|
353
|
+
});
|
|
354
|
+
/** Decode a hostile Release record through its canonical closed schema. */
|
|
355
|
+
export const decodeRelease = Schema.decodeUnknownResult(releaseSchema, {
|
|
356
|
+
onExcessProperty: "error",
|
|
357
|
+
});
|
|
358
|
+
/** Decode a hostile public Surface through its canonical closed schema. */
|
|
359
|
+
export const decodePublicSurface = Schema.decodeUnknownResult(publicSurfaceSchema, { onExcessProperty: "error" });
|
|
360
|
+
export const decodePublicSurfaceDefinition = Schema.decodeUnknownResult(publicSurfaceDefinitionSchema, { onExcessProperty: "error" });
|
|
361
|
+
/** Decode a hostile App-read store result through its canonical closed schema. */
|
|
362
|
+
export const decodeAppReadStoreResult = Schema.decodeUnknownResult(appReadStoreResultSchema, { onExcessProperty: "error" });
|
|
363
|
+
/** Decode a hostile App-create store result through its canonical closed schema. */
|
|
364
|
+
export const decodeAppCreateStoreResult = Schema.decodeUnknownResult(appCreateStoreResultSchema, { onExcessProperty: "error" });
|
|
365
|
+
/** Decode a hostile Release-read store result through its canonical closed schema. */
|
|
366
|
+
export const decodeReleaseReadStoreResult = Schema.decodeUnknownResult(releaseReadStoreResultSchema, { onExcessProperty: "error" });
|
|
367
|
+
/** Decode a hostile Release-create store result through its canonical closed schema. */
|
|
368
|
+
export const decodeReleaseCreateStoreResult = Schema.decodeUnknownResult(releaseCreateStoreResultSchema, { onExcessProperty: "error" });
|
|
369
|
+
/** Decode a hostile public-Surface-read store result through its canonical closed schema. */
|
|
370
|
+
export const decodePublicSurfaceReadStoreResult = Schema.decodeUnknownResult(publicSurfaceReadStoreResultSchema, { onExcessProperty: "error" });
|
|
371
|
+
/** Decode a hostile public-Surface-create store result through its canonical closed schema. */
|
|
372
|
+
export const decodePublicSurfaceCreateStoreResult = Schema.decodeUnknownResult(publicSurfaceCreateStoreResultSchema, { onExcessProperty: "error" });
|
|
373
|
+
/** Decode an owner-issued transition through its canonical closed schema. */
|
|
374
|
+
export const decodeReleaseTransition = Schema.decodeUnknownResult(releaseTransitionSchema, { onExcessProperty: "error" });
|
|
375
|
+
/** Decode a hostile Release lifecycle store result. */
|
|
376
|
+
export const decodeReleaseLifecycleStoreResult = Schema.decodeUnknownResult(releaseLifecycleStoreResultSchema, { onExcessProperty: "error" });
|
|
377
|
+
/** Decode a hostile verification-record store result. */
|
|
378
|
+
export const decodeReleaseVerificationRecordStoreResult = Schema.decodeUnknownResult(releaseVerificationRecordStoreResultSchema, {
|
|
379
|
+
onExcessProperty: "error",
|
|
380
|
+
});
|
|
381
|
+
/** Decode a hostile transition lookup store result. */
|
|
382
|
+
export const decodeTransitionLookupStoreResult = Schema.decodeUnknownResult(transitionLookupStoreResultSchema, { onExcessProperty: "error" });
|
|
383
|
+
/** Decode a hostile transition-persistence store result. */
|
|
384
|
+
export const decodeTransitionPersistenceStoreResult = Schema.decodeUnknownResult(transitionPersistenceStoreResultSchema, {
|
|
385
|
+
onExcessProperty: "error",
|
|
386
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import type { App, AppCreate, AppId, AppRead, AppReleaseStoreFailure, ReleaseLifecycle, PublicSurfaceDefinition, PublicSurfaceCreate, PublicSurfaceId, PublicSurfaceRead, Release, ReleaseCreate, ReleaseId, ReleaseRead, ReleaseTransition, Sha256Digest, VerifiedAppDescription, TransitionLookup, TransitionPersistence, TransitionReceipt } from "./app-release-contract.js";
|
|
3
|
+
/**
|
|
4
|
+
* Closed failures emitted by the owned Effect Store port.
|
|
5
|
+
*
|
|
6
|
+
* The invalid-result sentinel lets the outer Promise adapter fail closed when
|
|
7
|
+
* a foreign fulfilled value is not one of the catalog's durable outcomes.
|
|
8
|
+
*/
|
|
9
|
+
export type AppReleaseStorePortFailure = AppReleaseStoreFailure | {
|
|
10
|
+
readonly kind: "invalid-store-result";
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Canonical Effect-owned persistence port for the narrow App/Release catalog.
|
|
14
|
+
*
|
|
15
|
+
* Implementations own atomicity; the catalog owns the interpretation of these
|
|
16
|
+
* explicit outcomes. This port intentionally has no generic query or mutation
|
|
17
|
+
* escape hatch.
|
|
18
|
+
*/
|
|
19
|
+
export type AppReleaseStore = {
|
|
20
|
+
/** Look up exactly one Global App. */
|
|
21
|
+
readApp(appId: AppId): Effect.Effect<AppRead, AppReleaseStorePortFailure>;
|
|
22
|
+
/** Atomically create or observe exactly one Global App. */
|
|
23
|
+
createAppIfAbsent(app: App): Effect.Effect<AppCreate, AppReleaseStorePortFailure>;
|
|
24
|
+
/** Look up exactly one immutable Release. */
|
|
25
|
+
readRelease(releaseId: ReleaseId): Effect.Effect<ReleaseRead, AppReleaseStorePortFailure>;
|
|
26
|
+
/** Atomically create or observe exactly one immutable Release. */
|
|
27
|
+
createReleaseIfAbsent(release: Release): Effect.Effect<ReleaseCreate, AppReleaseStorePortFailure>;
|
|
28
|
+
/** Look up exactly one App-owned anonymous public Surface. */
|
|
29
|
+
readPublicSurface(publicSurfaceId: PublicSurfaceId): Effect.Effect<PublicSurfaceRead, AppReleaseStorePortFailure>;
|
|
30
|
+
/** Atomically create or observe one App-owned anonymous public Surface. */
|
|
31
|
+
createPublicSurfaceIfAbsent(surface: PublicSurfaceDefinition): Effect.Effect<PublicSurfaceCreate, AppReleaseStorePortFailure>;
|
|
32
|
+
/** Read the Release facts relevant to transition eligibility. */
|
|
33
|
+
readonly readReleaseLifecycle?: (releaseId: ReleaseId) => Effect.Effect<ReleaseLifecycle, AppReleaseStorePortFailure>;
|
|
34
|
+
/** Retain a verified artifact fact after core validation succeeds. */
|
|
35
|
+
readonly recordReleaseVerification?: (input: {
|
|
36
|
+
readonly releaseId: ReleaseId;
|
|
37
|
+
readonly digest: Sha256Digest;
|
|
38
|
+
readonly mediaType: "application/vnd.fungi.app+json";
|
|
39
|
+
readonly description: VerifiedAppDescription;
|
|
40
|
+
}) => Effect.Effect<{
|
|
41
|
+
readonly kind: "recorded";
|
|
42
|
+
}, AppReleaseStorePortFailure>;
|
|
43
|
+
/** Read a receipt or idempotency conflict before transition policy. */
|
|
44
|
+
readonly readTransition?: (request: ReleaseTransition) => Effect.Effect<TransitionLookup, AppReleaseStorePortFailure>;
|
|
45
|
+
/** Atomically persist a policy-approved transition and receipt. */
|
|
46
|
+
readonly persistTransition?: (request: ReleaseTransition, receipt: TransitionReceipt) => Effect.Effect<TransitionPersistence, AppReleaseStorePortFailure>;
|
|
47
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AppApi } from "../app-vocabulary.js";
|
|
2
|
+
/** A continuation must cover every write method's requirements, and itself be a write. */
|
|
3
|
+
export declare function backgroundSyncAllowed(api: Readonly<{
|
|
4
|
+
methods: Readonly<Record<string, Pick<AppApi["methods"][string], "effect" | "requires">>>;
|
|
5
|
+
}> | undefined, sync: Readonly<{
|
|
6
|
+
method: string;
|
|
7
|
+
}> | undefined): boolean;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** A continuation must cover every write method's requirements, and itself be a write. */
|
|
2
|
+
export function backgroundSyncAllowed(api, sync) {
|
|
3
|
+
if (sync === undefined)
|
|
4
|
+
return true;
|
|
5
|
+
const continuation = api?.methods[sync.method];
|
|
6
|
+
if (continuation?.effect !== "write")
|
|
7
|
+
return false;
|
|
8
|
+
return Object.values(api?.methods ?? {}).every((method) => method.effect !== "write" ||
|
|
9
|
+
method.requires.every((capability) => continuation.requires.includes(capability)));
|
|
10
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type PublicRouteConfiguration } from "../public-route-policy.js";
|
|
2
|
+
import type { TeamAppPublisherRegistration } from "../publisher.js";
|
|
3
|
+
import type { PromiseAppReleaseStore } from "./app-release-contract.js";
|
|
4
|
+
/**
|
|
5
|
+
* Compose an in-process deterministic store for the narrow App/Release port.
|
|
6
|
+
*
|
|
7
|
+
* Store methods mutate only the private collections below. Decisions remain in
|
|
8
|
+
* pure helpers, and every returned record is copied, so callers cannot mutate
|
|
9
|
+
* retained state after an atomic create-or-observe operation.
|
|
10
|
+
*/
|
|
11
|
+
export declare function createDeterministicMemoryAppReleaseStore(options?: {
|
|
12
|
+
readonly routes: PublicRouteConfiguration;
|
|
13
|
+
readonly publishers?: readonly TeamAppPublisherRegistration[];
|
|
14
|
+
}): PromiseAppReleaseStore;
|