domainkit 0.14.1 → 0.16.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.
- package/README.md +9 -2
- package/dist/Cloudflare.mjs +16 -7
- package/dist/Cloudflare.mjs.map +1 -1
- package/dist/Connect.mjs +5 -1
- package/dist/Connect.mjs.map +1 -1
- package/dist/Provider.mjs.map +1 -1
- package/dist/Provision.mjs +209 -19
- package/dist/Provision.mjs.map +1 -1
- package/dist/Reason.mjs +22 -2
- package/dist/Reason.mjs.map +1 -1
- package/dist/Server.mjs +89 -5
- package/dist/Server.mjs.map +1 -1
- package/dist/Storage.mjs +105 -2
- package/dist/Storage.mjs.map +1 -1
- package/dist/Testing.mjs +2 -0
- package/dist/Testing.mjs.map +1 -1
- package/dist/internal/attempts.mjs +14 -4
- package/dist/internal/attempts.mjs.map +1 -1
- package/dist/internal/conformance/provider.mjs +1 -0
- package/dist/internal/conformance/provider.mjs.map +1 -1
- package/dist/internal/conformance/storage.mjs +185 -0
- package/dist/internal/conformance/storage.mjs.map +1 -1
- package/dist/internal/error.mjs +2 -0
- package/dist/internal/error.mjs.map +1 -1
- package/dist/internal/storage-memory.mjs +185 -2
- package/dist/internal/storage-memory.mjs.map +1 -1
- package/dist/package.mjs +1 -1
- package/dist/types/Connect.d.ts +3 -1
- package/dist/types/Provider.d.ts +6 -0
- package/dist/types/Provision.d.ts +124 -3
- package/dist/types/Reason.d.ts +18 -2
- package/dist/types/Server.d.ts +3623 -202
- package/dist/types/Storage.d.ts +181 -0
- package/dist/types/Testing.d.ts +2 -0
- package/dist/types/internal/attempts.d.ts +1 -0
- package/dist/types/internal/error.d.ts +1 -1
- package/package.json +2 -2
package/dist/types/Storage.d.ts
CHANGED
|
@@ -38,6 +38,11 @@ declare const Authorization_base: Schema.Class<Authorization, Schema.Struct<{
|
|
|
38
38
|
readonly capabilities: Schema.$Array<Schema.Literals<readonly ["dns:read", "dns:write"]>>;
|
|
39
39
|
/** Provider-specific account context (account id, team id, ...) decoded by the provider's `context` schema. */
|
|
40
40
|
readonly context: Schema.Unknown;
|
|
41
|
+
/**
|
|
42
|
+
* What the provider called the account when the credential was issued, so a UI names the
|
|
43
|
+
* connection without a provider call. `null` when the provider names no single account.
|
|
44
|
+
*/
|
|
45
|
+
readonly label: Schema.NullOr<Schema.String>;
|
|
41
46
|
readonly revocation: Schema.Literals<readonly ["active", "pending", "revoked"]>;
|
|
42
47
|
readonly createdBy: Schema.String;
|
|
43
48
|
readonly createdAt: Schema.DateTimeUtcFromString;
|
|
@@ -125,6 +130,94 @@ declare const Attempt_base: Schema.Class<Attempt, Schema.Struct<{
|
|
|
125
130
|
/** One durable plan -> approval -> receipt lifecycle. */
|
|
126
131
|
export declare class Attempt extends Attempt_base {
|
|
127
132
|
}
|
|
133
|
+
export declare const BatchId: Schema.brand<Schema.String, "@domainkit/BatchId">;
|
|
134
|
+
export type BatchId = typeof BatchId.Type;
|
|
135
|
+
/**
|
|
136
|
+
* Where a batch stands, recomputed from its items' attempts after every transition.
|
|
137
|
+
*
|
|
138
|
+
* `planning` while any item is still without a plan, `planned` once every item carries one,
|
|
139
|
+
* `approved` once the principal bound the batch digest, then the apply states. `partial` and
|
|
140
|
+
* `failed` are resumable; `complete` and `rejected` are terminal and leave the unfinished index.
|
|
141
|
+
*/
|
|
142
|
+
export declare const BatchStatus: Schema.Literals<readonly ["planning", "planned", "approved", "applying", "complete", "partial", "failed", "rejected"]>;
|
|
143
|
+
export type BatchStatus = typeof BatchStatus.Type;
|
|
144
|
+
/** Who bound the batch to its digest, and when. The digest itself is `Batch.digest`. */
|
|
145
|
+
export declare const BatchApproval: Schema.Struct<{
|
|
146
|
+
readonly actorId: Schema.String;
|
|
147
|
+
readonly at: Schema.DateTimeUtcFromString;
|
|
148
|
+
}>;
|
|
149
|
+
export type BatchApproval = typeof BatchApproval.Type;
|
|
150
|
+
declare const Batch_base: Schema.Class<Batch, Schema.Struct<{
|
|
151
|
+
readonly id: Schema.brand<Schema.String, "@domainkit/BatchId">;
|
|
152
|
+
readonly ownerId: Schema.String;
|
|
153
|
+
readonly kind: Schema.Literals<readonly ["provisioning", "cleanup"]>;
|
|
154
|
+
readonly status: Schema.Literals<readonly ["planning", "planned", "approved", "applying", "complete", "partial", "failed", "rejected"]>;
|
|
155
|
+
/** SHA-256 over the items' `attachmentId:planDigest` pairs, bound at approval. */
|
|
156
|
+
readonly digest: Schema.NullOr<Schema.brand<Schema.String, "@domainkit/Digest">>;
|
|
157
|
+
readonly approval: Schema.NullOr<Schema.Struct<{
|
|
158
|
+
readonly actorId: Schema.String;
|
|
159
|
+
readonly at: Schema.DateTimeUtcFromString;
|
|
160
|
+
}>>;
|
|
161
|
+
readonly rejection: Schema.NullOr<Schema.Struct<{
|
|
162
|
+
readonly actorId: Schema.String;
|
|
163
|
+
readonly reason: Schema.NullOr<Schema.String>;
|
|
164
|
+
readonly at: Schema.DateTimeUtcFromString;
|
|
165
|
+
}>>;
|
|
166
|
+
/** Unique per owner: a replayed create returns the batch this key already made. */
|
|
167
|
+
readonly idempotencyKey: Schema.String;
|
|
168
|
+
readonly createdBy: Schema.String;
|
|
169
|
+
readonly createdAt: Schema.DateTimeUtcFromString;
|
|
170
|
+
readonly updatedAt: Schema.DateTimeUtcFromString;
|
|
171
|
+
/** When the batch reached `complete` or `rejected`; null while it still owes a move. */
|
|
172
|
+
readonly completedAt: Schema.NullOr<Schema.DateTimeUtcFromString>;
|
|
173
|
+
}>, {}>;
|
|
174
|
+
/**
|
|
175
|
+
* Many domains planned together, approved once, and applied with bounded concurrency.
|
|
176
|
+
*
|
|
177
|
+
* The batch owns the aggregate's own state only: its digest, who approved or declined it, and the
|
|
178
|
+
* status recomputed from its items. Every plan, approval, receipt, lease, and failure stays on the
|
|
179
|
+
* attempt an item points at, so nothing is stored twice.
|
|
180
|
+
*/
|
|
181
|
+
export declare class Batch extends Batch_base {
|
|
182
|
+
}
|
|
183
|
+
declare const BatchItem_base: Schema.Class<BatchItem, Schema.Struct<{
|
|
184
|
+
readonly batchId: Schema.brand<Schema.String, "@domainkit/BatchId">;
|
|
185
|
+
readonly attachmentId: Schema.String;
|
|
186
|
+
/** The item's place in the batch, as `create` received it. */
|
|
187
|
+
readonly position: Schema.Number;
|
|
188
|
+
readonly attemptId: Schema.NullOr<Schema.brand<Schema.String, "@domainkit/PlanId">>;
|
|
189
|
+
readonly planFailure: Schema.NullOr<Schema.String>;
|
|
190
|
+
}>, {}>;
|
|
191
|
+
/**
|
|
192
|
+
* One domain's place in a batch: a pointer to the attachment and to the attempt carrying its plan.
|
|
193
|
+
*
|
|
194
|
+
* `attemptId` is null until the item is planned, and `planFailure` carries why the last planning
|
|
195
|
+
* pass stopped, cleared the moment a plan lands.
|
|
196
|
+
*/
|
|
197
|
+
export declare class BatchItem extends BatchItem_base {
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* The status a batch holds, given whether it was approved or declined and where each item's
|
|
201
|
+
* attempt stands. `null` names an item that has no plan yet.
|
|
202
|
+
*
|
|
203
|
+
* Both `Storage` implementations recompute the stored status through this after every transition,
|
|
204
|
+
* so the owner-scoped unfinished index never disagrees with the attempts it summarizes.
|
|
205
|
+
*/
|
|
206
|
+
export declare const batchStatusOf: (input: {
|
|
207
|
+
readonly approved: boolean;
|
|
208
|
+
readonly rejected: boolean;
|
|
209
|
+
readonly items: ReadonlyArray<AttemptStatus | null>;
|
|
210
|
+
}) => BatchStatus;
|
|
211
|
+
/** A batch with its items, in `position` order. Every batch read returns one. */
|
|
212
|
+
export interface BatchAggregate {
|
|
213
|
+
readonly batch: Batch;
|
|
214
|
+
readonly items: ReadonlyArray<BatchItem>;
|
|
215
|
+
}
|
|
216
|
+
/** One item's attempt approval, as `batches.approve` writes it beside the batch's own. */
|
|
217
|
+
export interface BatchItemApproval {
|
|
218
|
+
readonly attachmentId: string;
|
|
219
|
+
readonly approval: Approval.Model;
|
|
220
|
+
}
|
|
128
221
|
export declare const RequirementStatus: Schema.Literals<readonly ["satisfied", "missing", "mismatch", "unknown"]>;
|
|
129
222
|
export type RequirementStatus = typeof RequirementStatus.Type;
|
|
130
223
|
export declare const Overall: Schema.Literals<readonly ["ready", "pending", "failed"]>;
|
|
@@ -242,6 +335,72 @@ export interface Interface {
|
|
|
242
335
|
readonly complete: (id: Plan.PlanId, receipt: Receipt.Model) => Fx<Attempt>;
|
|
243
336
|
readonly fail: (id: Plan.PlanId, message: string) => Fx<Attempt>;
|
|
244
337
|
};
|
|
338
|
+
/**
|
|
339
|
+
* The batch aggregate: many attempts planned together and approved once.
|
|
340
|
+
*
|
|
341
|
+
* Every transition runs in one transaction over the locked batch row and leaves `status`
|
|
342
|
+
* recomputed from the items' attempts, so the owner-scoped unfinished index never disagrees
|
|
343
|
+
* with the attempts it summarizes.
|
|
344
|
+
*/
|
|
345
|
+
readonly batches: {
|
|
346
|
+
/**
|
|
347
|
+
* Insert the batch and one item per attachment, or return the batch this owner already
|
|
348
|
+
* created under `idempotencyKey`. A replay ignores `attachmentIds` and returns what is
|
|
349
|
+
* stored, which is what makes a retried create safe.
|
|
350
|
+
*/
|
|
351
|
+
readonly create: (input: {
|
|
352
|
+
readonly kind: Plan.Kind;
|
|
353
|
+
readonly idempotencyKey: string;
|
|
354
|
+
/** One item per attachment, in order; empty or duplicated fails `InvalidInput`. */
|
|
355
|
+
readonly attachmentIds: ReadonlyArray<string>;
|
|
356
|
+
}) => Fx<BatchAggregate>;
|
|
357
|
+
readonly get: (id: BatchId) => Fx<BatchAggregate>;
|
|
358
|
+
/**
|
|
359
|
+
* The batch this owner created under `idempotencyKey`, if any.
|
|
360
|
+
*
|
|
361
|
+
* What a caller reads before it validates a create's payload, so a retried request answers
|
|
362
|
+
* with the batch the first one made whatever the retry now says.
|
|
363
|
+
*/
|
|
364
|
+
readonly byIdempotencyKey: (key: string) => Fx<Option.Option<BatchAggregate>>;
|
|
365
|
+
/** Every batch that has not reached `complete` or `rejected`, most recently touched first. */
|
|
366
|
+
readonly listUnfinished: () => Fx<ReadonlyArray<BatchAggregate>>;
|
|
367
|
+
/**
|
|
368
|
+
* Point an item at the attempt that now carries its plan and clear its plan failure.
|
|
369
|
+
*
|
|
370
|
+
* Fails `Stale` unless the batch is still `planning` or `planned`. That check is the fence a
|
|
371
|
+
* planner still in flight hits when the principal declines the batch underneath it, so plan
|
|
372
|
+
* state never lands on a rejected aggregate.
|
|
373
|
+
*/
|
|
374
|
+
readonly recordItemPlan: (id: BatchId, attachmentId: string, attemptId: Plan.PlanId) => Fx<BatchAggregate>;
|
|
375
|
+
/** Record why an item could not be planned; the batch stays `planning`. Same fence. */
|
|
376
|
+
readonly recordItemPlanFailure: (id: BatchId, attachmentId: string, message: string) => Fx<BatchAggregate>;
|
|
377
|
+
/**
|
|
378
|
+
* Bind the batch to `digest` and approve every item's attempt in the same transaction, so a
|
|
379
|
+
* batch is never approved without the per-attempt approvals `attempts.apply` needs.
|
|
380
|
+
*
|
|
381
|
+
* Fails `Stale` unless the batch is `planned` and every item still points at the attempt its
|
|
382
|
+
* approval names. Approving an approved batch under the same digest returns it unchanged; a
|
|
383
|
+
* different digest fails `Stale`.
|
|
384
|
+
*/
|
|
385
|
+
readonly approve: (id: BatchId, input: {
|
|
386
|
+
readonly digest: Plan.Digest;
|
|
387
|
+
readonly actorId: string;
|
|
388
|
+
/** One per item, covering every item in the batch. */
|
|
389
|
+
readonly approvals: ReadonlyArray<BatchItemApproval>;
|
|
390
|
+
}) => Fx<BatchAggregate>;
|
|
391
|
+
/**
|
|
392
|
+
* Decline the batch and every planned attempt under it, in one transaction. Terminal.
|
|
393
|
+
*
|
|
394
|
+
* Rejecting again returns the batch unchanged; a batch that reached `approved` or later
|
|
395
|
+
* fails `Stale`.
|
|
396
|
+
*/
|
|
397
|
+
readonly reject: (id: BatchId, input: {
|
|
398
|
+
readonly actorId: string;
|
|
399
|
+
readonly reason: string | null;
|
|
400
|
+
}) => Fx<BatchAggregate>;
|
|
401
|
+
/** Recompute the stored status from the items' attempts, after applying moved them. */
|
|
402
|
+
readonly refresh: (id: BatchId) => Fx<BatchAggregate>;
|
|
403
|
+
};
|
|
245
404
|
readonly readiness: {
|
|
246
405
|
/** One row per (owner, domain); `attachmentId`, when set, must exist for the owner. */
|
|
247
406
|
readonly put: (readiness: Readiness) => Fx<void>;
|
|
@@ -329,6 +488,28 @@ export interface AsyncInterface {
|
|
|
329
488
|
readonly complete: (principal: Principal.Interface, id: Plan.PlanId, receipt: Receipt.Model) => Promise<Attempt>;
|
|
330
489
|
readonly fail: (principal: Principal.Interface, id: Plan.PlanId, message: string) => Promise<Attempt>;
|
|
331
490
|
};
|
|
491
|
+
readonly batches: {
|
|
492
|
+
readonly create: (principal: Principal.Interface, input: {
|
|
493
|
+
readonly kind: Plan.Kind;
|
|
494
|
+
readonly idempotencyKey: string;
|
|
495
|
+
readonly attachmentIds: ReadonlyArray<string>;
|
|
496
|
+
}) => Promise<BatchAggregate>;
|
|
497
|
+
readonly get: (principal: Principal.Interface, id: BatchId) => Promise<BatchAggregate>;
|
|
498
|
+
readonly byIdempotencyKey: (principal: Principal.Interface, key: string) => Promise<BatchAggregate | null>;
|
|
499
|
+
readonly listUnfinished: (principal: Principal.Interface) => Promise<ReadonlyArray<BatchAggregate>>;
|
|
500
|
+
readonly recordItemPlan: (principal: Principal.Interface, id: BatchId, attachmentId: string, attemptId: Plan.PlanId) => Promise<BatchAggregate>;
|
|
501
|
+
readonly recordItemPlanFailure: (principal: Principal.Interface, id: BatchId, attachmentId: string, message: string) => Promise<BatchAggregate>;
|
|
502
|
+
readonly approve: (principal: Principal.Interface, id: BatchId, input: {
|
|
503
|
+
readonly digest: Plan.Digest;
|
|
504
|
+
readonly actorId: string;
|
|
505
|
+
readonly approvals: ReadonlyArray<BatchItemApproval>;
|
|
506
|
+
}) => Promise<BatchAggregate>;
|
|
507
|
+
readonly reject: (principal: Principal.Interface, id: BatchId, input: {
|
|
508
|
+
readonly actorId: string;
|
|
509
|
+
readonly reason: string | null;
|
|
510
|
+
}) => Promise<BatchAggregate>;
|
|
511
|
+
readonly refresh: (principal: Principal.Interface, id: BatchId) => Promise<BatchAggregate>;
|
|
512
|
+
};
|
|
332
513
|
readonly readiness: {
|
|
333
514
|
readonly put: (principal: Principal.Interface, readiness: Readiness) => Promise<void>;
|
|
334
515
|
readonly get: (principal: Principal.Interface, domain: string) => Promise<Readiness | null>;
|
package/dist/types/Testing.d.ts
CHANGED
|
@@ -22,6 +22,8 @@ export interface FakeProviderOptions {
|
|
|
22
22
|
readonly zones?: ReadonlyArray<string>;
|
|
23
23
|
/** The label each zone carries, keyed by zone. Default: the zone name. */
|
|
24
24
|
readonly labels?: Readonly<Record<string, string>>;
|
|
25
|
+
/** What the fake calls the account it issues credentials for. Default: none, so the label is `null`. */
|
|
26
|
+
readonly accountLabel?: string;
|
|
25
27
|
/** Pre-existing records, to produce `Noop` and `Conflict` operations. */
|
|
26
28
|
readonly records?: ReadonlyArray<{
|
|
27
29
|
readonly zone: string;
|
|
@@ -29,6 +29,7 @@ export declare const make: (storage: Storage.Interface, connect: Connect.Interfa
|
|
|
29
29
|
readonly sourceReceiptId: Receipt.ReceiptId | null;
|
|
30
30
|
}) => Fx<Plan.Model>;
|
|
31
31
|
approve: (plan: Plan.Model | Plan.PlanId, options?: ApproveOptions) => Fx<Approval.Model>;
|
|
32
|
+
draftApproval: (attempt: Storage.Attempt, options?: ApproveOptions) => Fx<Approval.Model>;
|
|
32
33
|
reject: (plan: Plan.Model | Plan.PlanId, options?: {
|
|
33
34
|
readonly reason?: string;
|
|
34
35
|
}) => Fx<Storage.Attempt>;
|
|
@@ -7,7 +7,7 @@ import { Effect, Schema } from "effect";
|
|
|
7
7
|
import * as Reason from "../Reason.ts";
|
|
8
8
|
export type Category = "request" | "auth" | "plan" | "provider" | "storage" | "internal";
|
|
9
9
|
declare const DomainKitError_base: Schema.Class<DomainKitError, Schema.TaggedStruct<"DomainKitError", {
|
|
10
|
-
readonly reason: Schema.suspend<Schema.Union<readonly [typeof Reason.InvalidInput, typeof Reason.Unauthenticated, typeof Reason.Forbidden, typeof Reason.NotFound, typeof Reason.Conflict, typeof Reason.Stale, typeof Reason.Expired, typeof Reason.Busy, typeof Reason.ProviderRejected, typeof Reason.ProviderUnavailable, typeof Reason.ProviderConflict, typeof Reason.Unsupported, typeof Reason.Reconnect, typeof Reason.StorageFailed, typeof Reason.CryptoFailed, typeof Reason.ResolverFailed]>>;
|
|
10
|
+
readonly reason: Schema.suspend<Schema.Union<readonly [typeof Reason.InvalidInput, typeof Reason.Unauthenticated, typeof Reason.Forbidden, typeof Reason.NotFound, typeof Reason.Conflict, typeof Reason.Stale, typeof Reason.BatchStale, typeof Reason.Expired, typeof Reason.Busy, typeof Reason.ProviderRejected, typeof Reason.ProviderUnavailable, typeof Reason.ProviderConflict, typeof Reason.Unsupported, typeof Reason.Reconnect, typeof Reason.StorageFailed, typeof Reason.CryptoFailed, typeof Reason.ResolverFailed]>>;
|
|
11
11
|
}>, import("effect/Cause").YieldableError>;
|
|
12
12
|
export declare class DomainKitError extends DomainKitError_base {
|
|
13
13
|
get category(): Category;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "domainkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Build reviewable DNS plans for custom domains in TypeScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"custom-domains",
|
|
@@ -157,5 +157,5 @@
|
|
|
157
157
|
"engines": {
|
|
158
158
|
"node": ">=24.10.0"
|
|
159
159
|
},
|
|
160
|
-
"packageManager": "bun@1.4.
|
|
160
|
+
"packageManager": "bun@1.4.2"
|
|
161
161
|
}
|