domainkit 0.13.0 → 0.14.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.
@@ -342,6 +342,8 @@ export declare const Readiness: Schema.Struct<{
342
342
  readonly attachmentId: Schema.NullOr<Schema.String>;
343
343
  readonly overall: Schema.Literals<readonly ["ready", "pending", "failed"]>;
344
344
  readonly requirements: Schema.$Array<Schema.Struct<{
345
+ /** `Verify.requirementKey(record)`, so a client pairs rows by content, not by position. */
346
+ readonly key: Schema.String;
345
347
  readonly operationId: Schema.NullOr<Schema.brand<Schema.String, "@domainkit/OperationId">>;
346
348
  readonly record: Schema.Union<readonly [typeof DnsRecord.A, typeof DnsRecord.AAAA, typeof DnsRecord.CNAME, typeof DnsRecord.TXT, typeof DnsRecord.MX, typeof DnsRecord.CAA, typeof DnsRecord.NS, typeof DnsRecord.SRV]>;
347
349
  readonly status: Schema.Literals<readonly ["satisfied", "missing", "mismatch", "unknown"]>;
@@ -4508,6 +4510,8 @@ export declare const group: HttpApiGroup.HttpApiGroup<"domainkit", HttpApiEndpoi
4508
4510
  readonly attachmentId: Schema.NullOr<Schema.String>;
4509
4511
  readonly overall: Schema.Literals<readonly ["ready", "pending", "failed"]>;
4510
4512
  readonly requirements: Schema.$Array<Schema.Struct<{
4513
+ /** `Verify.requirementKey(record)`, so a client pairs rows by content, not by position. */
4514
+ readonly key: Schema.String;
4511
4515
  readonly operationId: Schema.NullOr<Schema.brand<Schema.String, "@domainkit/OperationId">>;
4512
4516
  readonly record: Schema.Union<readonly [typeof DnsRecord.A, typeof DnsRecord.AAAA, typeof DnsRecord.CNAME, typeof DnsRecord.TXT, typeof DnsRecord.MX, typeof DnsRecord.CAA, typeof DnsRecord.NS, typeof DnsRecord.SRV]>;
4513
4517
  readonly status: Schema.Literals<readonly ["satisfied", "missing", "mismatch", "unknown"]>;
@@ -5344,6 +5348,431 @@ export declare const group: HttpApiGroup.HttpApiGroup<"domainkit", HttpApiEndpoi
5344
5348
  };
5345
5349
  }>, Schema.TaggedStruct<"DomainKitError", {
5346
5350
  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]>>;
5351
+ }>, never, never>>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"readiness", "GET", "/domains/:domain/readiness", Schema.toCodecStringTree<Schema.Struct<{
5352
+ domain: Schema.String;
5353
+ }>>, never, never, never, Schema.toCodecJson<Schema.NullOr<Schema.Struct<{
5354
+ readonly domain: Schema.String;
5355
+ readonly attachmentId: Schema.NullOr<Schema.String>;
5356
+ readonly overall: Schema.Literals<readonly ["ready", "pending", "failed"]>;
5357
+ readonly requirements: Schema.$Array<Schema.Struct<{
5358
+ /** `Verify.requirementKey(record)`, so a client pairs rows by content, not by position. */
5359
+ readonly key: Schema.String;
5360
+ readonly operationId: Schema.NullOr<Schema.brand<Schema.String, "@domainkit/OperationId">>;
5361
+ readonly record: Schema.Union<readonly [typeof DnsRecord.A, typeof DnsRecord.AAAA, typeof DnsRecord.CNAME, typeof DnsRecord.TXT, typeof DnsRecord.MX, typeof DnsRecord.CAA, typeof DnsRecord.NS, typeof DnsRecord.SRV]>;
5362
+ readonly status: Schema.Literals<readonly ["satisfied", "missing", "mismatch", "unknown"]>;
5363
+ readonly evidence: Schema.$Array<Schema.Union<readonly [typeof Verify.ProviderEvidence, typeof Verify.PublicDnsEvidence, typeof Verify.HostEvidence]>>;
5364
+ }>>;
5365
+ readonly host: Schema.$Array<typeof Verify.HostEvidence>;
5366
+ readonly checkedAt: Schema.DateTimeUtcFromString;
5367
+ readonly nextCheckAt: Schema.NullOr<Schema.DateTimeUtcFromString>;
5368
+ }>>>, Schema.toCodecJson<Schema.decodeTo<Schema.declareConstructor<Errors.DomainKitError, {
5369
+ readonly _tag: "DomainKitError";
5370
+ readonly reason: {
5371
+ readonly _tag: "InvalidInput";
5372
+ readonly message: string;
5373
+ readonly field?: string;
5374
+ } | {
5375
+ readonly _tag: "Unauthenticated";
5376
+ readonly message: string;
5377
+ } | {
5378
+ readonly _tag: "Forbidden";
5379
+ readonly message: string;
5380
+ } | {
5381
+ readonly _tag: "NotFound";
5382
+ readonly entity: "approval" | "attachment" | "authorization" | "connection" | "continuation" | "plan" | "provider" | "receipt" | "record" | "zone";
5383
+ readonly id: string;
5384
+ } | {
5385
+ readonly _tag: "Conflict";
5386
+ readonly planId: string;
5387
+ readonly operations: readonly {
5388
+ readonly _tag: "Conflict";
5389
+ readonly id: string;
5390
+ readonly record: {
5391
+ readonly _tag: "A";
5392
+ readonly name: string;
5393
+ readonly ttl: number | null;
5394
+ readonly policy: "append" | "exclusive";
5395
+ readonly purpose?: string;
5396
+ readonly address: string;
5397
+ } | {
5398
+ readonly _tag: "AAAA";
5399
+ readonly name: string;
5400
+ readonly ttl: number | null;
5401
+ readonly policy: "append" | "exclusive";
5402
+ readonly purpose?: string;
5403
+ readonly address: string;
5404
+ } | {
5405
+ readonly _tag: "CNAME";
5406
+ readonly name: string;
5407
+ readonly ttl: number | null;
5408
+ readonly policy: "append" | "exclusive";
5409
+ readonly purpose?: string;
5410
+ readonly target: string;
5411
+ } | {
5412
+ readonly _tag: "TXT";
5413
+ readonly name: string;
5414
+ readonly ttl: number | null;
5415
+ readonly policy: "append" | "exclusive";
5416
+ readonly purpose?: string;
5417
+ readonly value: string;
5418
+ } | {
5419
+ readonly _tag: "MX";
5420
+ readonly name: string;
5421
+ readonly ttl: number | null;
5422
+ readonly policy: "append" | "exclusive";
5423
+ readonly purpose?: string;
5424
+ readonly exchange: string;
5425
+ readonly priority: number;
5426
+ } | {
5427
+ readonly _tag: "CAA";
5428
+ readonly name: string;
5429
+ readonly ttl: number | null;
5430
+ readonly policy: "append" | "exclusive";
5431
+ readonly purpose?: string;
5432
+ readonly flags: number;
5433
+ readonly tag: string;
5434
+ readonly value: string;
5435
+ } | {
5436
+ readonly _tag: "NS";
5437
+ readonly name: string;
5438
+ readonly ttl: number | null;
5439
+ readonly policy: "append" | "exclusive";
5440
+ readonly purpose?: string;
5441
+ readonly nameserver: string;
5442
+ } | {
5443
+ readonly _tag: "SRV";
5444
+ readonly name: string;
5445
+ readonly ttl: number | null;
5446
+ readonly policy: "append" | "exclusive";
5447
+ readonly purpose?: string;
5448
+ readonly target: string;
5449
+ readonly port: number;
5450
+ readonly priority: number;
5451
+ readonly weight: number;
5452
+ };
5453
+ readonly existing: readonly ({
5454
+ readonly _tag: "A";
5455
+ readonly name: string;
5456
+ readonly ttl: number | null;
5457
+ readonly policy: "append" | "exclusive";
5458
+ readonly purpose?: string;
5459
+ readonly address: string;
5460
+ } | {
5461
+ readonly _tag: "AAAA";
5462
+ readonly name: string;
5463
+ readonly ttl: number | null;
5464
+ readonly policy: "append" | "exclusive";
5465
+ readonly purpose?: string;
5466
+ readonly address: string;
5467
+ } | {
5468
+ readonly _tag: "CNAME";
5469
+ readonly name: string;
5470
+ readonly ttl: number | null;
5471
+ readonly policy: "append" | "exclusive";
5472
+ readonly purpose?: string;
5473
+ readonly target: string;
5474
+ } | {
5475
+ readonly _tag: "TXT";
5476
+ readonly name: string;
5477
+ readonly ttl: number | null;
5478
+ readonly policy: "append" | "exclusive";
5479
+ readonly purpose?: string;
5480
+ readonly value: string;
5481
+ } | {
5482
+ readonly _tag: "MX";
5483
+ readonly name: string;
5484
+ readonly ttl: number | null;
5485
+ readonly policy: "append" | "exclusive";
5486
+ readonly purpose?: string;
5487
+ readonly exchange: string;
5488
+ readonly priority: number;
5489
+ } | {
5490
+ readonly _tag: "CAA";
5491
+ readonly name: string;
5492
+ readonly ttl: number | null;
5493
+ readonly policy: "append" | "exclusive";
5494
+ readonly purpose?: string;
5495
+ readonly flags: number;
5496
+ readonly tag: string;
5497
+ readonly value: string;
5498
+ } | {
5499
+ readonly _tag: "NS";
5500
+ readonly name: string;
5501
+ readonly ttl: number | null;
5502
+ readonly policy: "append" | "exclusive";
5503
+ readonly purpose?: string;
5504
+ readonly nameserver: string;
5505
+ } | {
5506
+ readonly _tag: "SRV";
5507
+ readonly name: string;
5508
+ readonly ttl: number | null;
5509
+ readonly policy: "append" | "exclusive";
5510
+ readonly purpose?: string;
5511
+ readonly target: string;
5512
+ readonly port: number;
5513
+ readonly priority: number;
5514
+ readonly weight: number;
5515
+ } | {
5516
+ readonly _tag: "Opaque";
5517
+ readonly name: string;
5518
+ readonly type: string;
5519
+ readonly raw: unknown;
5520
+ })[];
5521
+ readonly reason: "cname-collision" | "exclusive-name" | "missing" | "opaque" | "value-mismatch";
5522
+ }[];
5523
+ } | {
5524
+ readonly _tag: "Stale";
5525
+ readonly planId: string;
5526
+ readonly digest: string;
5527
+ } | {
5528
+ readonly _tag: "Expired";
5529
+ readonly entity: "approval" | "continuation" | "credential" | "plan";
5530
+ readonly id: string;
5531
+ } | {
5532
+ readonly _tag: "Busy";
5533
+ readonly key: string;
5534
+ } | {
5535
+ readonly _tag: "ProviderRejected";
5536
+ readonly provider: string;
5537
+ readonly code?: string;
5538
+ readonly message: string;
5539
+ } | {
5540
+ readonly _tag: "ProviderUnavailable";
5541
+ readonly provider: string;
5542
+ readonly retryAfterMs?: number;
5543
+ readonly message: string;
5544
+ } | {
5545
+ readonly _tag: "ProviderConflict";
5546
+ readonly provider: string;
5547
+ readonly code?: string;
5548
+ readonly message: string;
5549
+ } | {
5550
+ readonly _tag: "Unsupported";
5551
+ readonly provider: string;
5552
+ readonly operation: string;
5553
+ readonly message: string;
5554
+ } | {
5555
+ readonly _tag: "Reconnect";
5556
+ readonly provider: string;
5557
+ readonly connectionId: string;
5558
+ } | {
5559
+ readonly _tag: "StorageFailed";
5560
+ readonly operation: string;
5561
+ readonly message: string;
5562
+ } | {
5563
+ readonly _tag: "CryptoFailed";
5564
+ readonly operation: "digest" | "open" | "seal";
5565
+ } | {
5566
+ readonly _tag: "ResolverFailed";
5567
+ readonly resolver: string;
5568
+ readonly message: string;
5569
+ };
5570
+ }, readonly [Schema.TaggedStruct<"DomainKitError", {
5571
+ 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]>>;
5572
+ }>], {
5573
+ readonly _tag: "DomainKitError";
5574
+ readonly reason: {
5575
+ readonly _tag: "InvalidInput";
5576
+ readonly message: string;
5577
+ readonly field?: string;
5578
+ } | {
5579
+ readonly _tag: "Unauthenticated";
5580
+ readonly message: string;
5581
+ } | {
5582
+ readonly _tag: "Forbidden";
5583
+ readonly message: string;
5584
+ } | {
5585
+ readonly _tag: "NotFound";
5586
+ readonly entity: "approval" | "attachment" | "authorization" | "connection" | "continuation" | "plan" | "provider" | "receipt" | "record" | "zone";
5587
+ readonly id: string;
5588
+ } | {
5589
+ readonly _tag: "Conflict";
5590
+ readonly planId: string & import("effect/Brand").Brand<"@domainkit/PlanId">;
5591
+ readonly operations: readonly {
5592
+ readonly _tag: "Conflict";
5593
+ readonly id: string & import("effect/Brand").Brand<"@domainkit/OperationId">;
5594
+ readonly record: {
5595
+ readonly _tag: "A";
5596
+ readonly name: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5597
+ readonly ttl: number | null;
5598
+ readonly policy: "append" | "exclusive";
5599
+ readonly purpose?: string;
5600
+ readonly address: string;
5601
+ } | {
5602
+ readonly _tag: "AAAA";
5603
+ readonly name: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5604
+ readonly ttl: number | null;
5605
+ readonly policy: "append" | "exclusive";
5606
+ readonly purpose?: string;
5607
+ readonly address: string;
5608
+ } | {
5609
+ readonly _tag: "CNAME";
5610
+ readonly name: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5611
+ readonly ttl: number | null;
5612
+ readonly policy: "append" | "exclusive";
5613
+ readonly purpose?: string;
5614
+ readonly target: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5615
+ } | {
5616
+ readonly _tag: "TXT";
5617
+ readonly name: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5618
+ readonly ttl: number | null;
5619
+ readonly policy: "append" | "exclusive";
5620
+ readonly purpose?: string;
5621
+ readonly value: string;
5622
+ } | {
5623
+ readonly _tag: "MX";
5624
+ readonly name: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5625
+ readonly ttl: number | null;
5626
+ readonly policy: "append" | "exclusive";
5627
+ readonly purpose?: string;
5628
+ readonly exchange: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5629
+ readonly priority: number;
5630
+ } | {
5631
+ readonly _tag: "CAA";
5632
+ readonly name: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5633
+ readonly ttl: number | null;
5634
+ readonly policy: "append" | "exclusive";
5635
+ readonly purpose?: string;
5636
+ readonly flags: number;
5637
+ readonly tag: string;
5638
+ readonly value: string;
5639
+ } | {
5640
+ readonly _tag: "NS";
5641
+ readonly name: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5642
+ readonly ttl: number | null;
5643
+ readonly policy: "append" | "exclusive";
5644
+ readonly purpose?: string;
5645
+ readonly nameserver: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5646
+ } | {
5647
+ readonly _tag: "SRV";
5648
+ readonly name: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5649
+ readonly ttl: number | null;
5650
+ readonly policy: "append" | "exclusive";
5651
+ readonly purpose?: string;
5652
+ readonly target: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5653
+ readonly port: number;
5654
+ readonly priority: number;
5655
+ readonly weight: number;
5656
+ };
5657
+ readonly existing: readonly ({
5658
+ readonly _tag: "A";
5659
+ readonly name: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5660
+ readonly ttl: number | null;
5661
+ readonly policy: "append" | "exclusive";
5662
+ readonly purpose?: string;
5663
+ readonly address: string;
5664
+ } | {
5665
+ readonly _tag: "AAAA";
5666
+ readonly name: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5667
+ readonly ttl: number | null;
5668
+ readonly policy: "append" | "exclusive";
5669
+ readonly purpose?: string;
5670
+ readonly address: string;
5671
+ } | {
5672
+ readonly _tag: "CNAME";
5673
+ readonly name: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5674
+ readonly ttl: number | null;
5675
+ readonly policy: "append" | "exclusive";
5676
+ readonly purpose?: string;
5677
+ readonly target: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5678
+ } | {
5679
+ readonly _tag: "TXT";
5680
+ readonly name: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5681
+ readonly ttl: number | null;
5682
+ readonly policy: "append" | "exclusive";
5683
+ readonly purpose?: string;
5684
+ readonly value: string;
5685
+ } | {
5686
+ readonly _tag: "MX";
5687
+ readonly name: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5688
+ readonly ttl: number | null;
5689
+ readonly policy: "append" | "exclusive";
5690
+ readonly purpose?: string;
5691
+ readonly exchange: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5692
+ readonly priority: number;
5693
+ } | {
5694
+ readonly _tag: "CAA";
5695
+ readonly name: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5696
+ readonly ttl: number | null;
5697
+ readonly policy: "append" | "exclusive";
5698
+ readonly purpose?: string;
5699
+ readonly flags: number;
5700
+ readonly tag: string;
5701
+ readonly value: string;
5702
+ } | {
5703
+ readonly _tag: "NS";
5704
+ readonly name: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5705
+ readonly ttl: number | null;
5706
+ readonly policy: "append" | "exclusive";
5707
+ readonly purpose?: string;
5708
+ readonly nameserver: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5709
+ } | {
5710
+ readonly _tag: "SRV";
5711
+ readonly name: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5712
+ readonly ttl: number | null;
5713
+ readonly policy: "append" | "exclusive";
5714
+ readonly purpose?: string;
5715
+ readonly target: string & import("effect/Brand").Brand<"@domainkit/DomainName">;
5716
+ readonly port: number;
5717
+ readonly priority: number;
5718
+ readonly weight: number;
5719
+ } | {
5720
+ readonly _tag: "Opaque";
5721
+ readonly name: string;
5722
+ readonly type: string;
5723
+ readonly raw: unknown;
5724
+ })[];
5725
+ readonly reason: "cname-collision" | "exclusive-name" | "missing" | "opaque" | "value-mismatch";
5726
+ }[];
5727
+ } | {
5728
+ readonly _tag: "Stale";
5729
+ readonly planId: string & import("effect/Brand").Brand<"@domainkit/PlanId">;
5730
+ readonly digest: string & import("effect/Brand").Brand<"@domainkit/Digest">;
5731
+ } | {
5732
+ readonly _tag: "Expired";
5733
+ readonly entity: "approval" | "continuation" | "credential" | "plan";
5734
+ readonly id: string;
5735
+ } | {
5736
+ readonly _tag: "Busy";
5737
+ readonly key: string;
5738
+ } | {
5739
+ readonly _tag: "ProviderRejected";
5740
+ readonly provider: string;
5741
+ readonly code?: string;
5742
+ readonly message: string;
5743
+ } | {
5744
+ readonly _tag: "ProviderUnavailable";
5745
+ readonly provider: string;
5746
+ readonly retryAfterMs?: number;
5747
+ readonly message: string;
5748
+ } | {
5749
+ readonly _tag: "ProviderConflict";
5750
+ readonly provider: string;
5751
+ readonly code?: string;
5752
+ readonly message: string;
5753
+ } | {
5754
+ readonly _tag: "Unsupported";
5755
+ readonly provider: string;
5756
+ readonly operation: string;
5757
+ readonly message: string;
5758
+ } | {
5759
+ readonly _tag: "Reconnect";
5760
+ readonly provider: string;
5761
+ readonly connectionId: string;
5762
+ } | {
5763
+ readonly _tag: "StorageFailed";
5764
+ readonly operation: string;
5765
+ readonly message: string;
5766
+ } | {
5767
+ readonly _tag: "CryptoFailed";
5768
+ readonly operation: "digest" | "open" | "seal";
5769
+ } | {
5770
+ readonly _tag: "ResolverFailed";
5771
+ readonly resolver: string;
5772
+ readonly message: string;
5773
+ };
5774
+ }>, Schema.TaggedStruct<"DomainKitError", {
5775
+ 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]>>;
5347
5776
  }>, never, never>>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"receipt", "GET", "/receipts/:receiptId", Schema.toCodecStringTree<Schema.Struct<{
5348
5777
  receiptId: Schema.brand<Schema.String, "@domainkit/ReceiptId">;
5349
5778
  }>>, never, never, never, Schema.toCodecJson<typeof Receipt.Model>, Schema.toCodecJson<Schema.decodeTo<Schema.declareConstructor<Errors.DomainKitError, {
@@ -95,6 +95,8 @@ export interface VerificationGroup {
95
95
  readonly observe: (domain: string, options?: {
96
96
  readonly requirements?: ReadonlyArray<DnsRecord.Model>;
97
97
  }) => Fx<Readiness>;
98
+ /** The stored readiness, without observing. `null` until the domain has been observed once. */
99
+ readonly latest: (domain: string) => Fx<Readiness | null>;
98
100
  }
99
101
  export interface CleanupGroup {
100
102
  readonly plan: (receiptId: Receipt.ReceiptId) => Fx<Plan.Model>;
@@ -42,6 +42,8 @@ export declare class HostEvidence extends HostEvidence_base {
42
42
  export declare const Evidence: Schema.Union<readonly [typeof ProviderEvidence, typeof PublicDnsEvidence, typeof HostEvidence]>;
43
43
  export type Evidence = typeof Evidence.Type;
44
44
  export interface Requirement {
45
+ /** `requirementKey(record)`: what a host pairs its own row against, by content. */
46
+ readonly key: string;
45
47
  readonly operationId: Plan.OperationId | null;
46
48
  readonly record: DnsRecord.Model;
47
49
  readonly status: Storage.RequirementStatus;
@@ -81,6 +83,32 @@ export interface Interface {
81
83
  declare const Service_base: Context.ServiceClass<Service, "@domainkit/Verify", Interface>;
82
84
  export declare class Service extends Service_base {
83
85
  }
86
+ /**
87
+ * A requirement's identity: the record's type, name, and data, and nothing else. It is what a host
88
+ * pairs its own rows against readiness by, instead of trusting the order of the array.
89
+ * `@domainkit/react`'s `Records.identity` is this function.
90
+ */
91
+ export declare const requirementKey: (record: DnsRecord.Model) => string;
92
+ /** Counts across a readiness's requirements. `observed` is false when there is no readiness yet. */
93
+ export interface Summary {
94
+ readonly observed: boolean;
95
+ readonly total: number;
96
+ readonly satisfied: number;
97
+ readonly missing: number;
98
+ readonly mismatch: number;
99
+ readonly unknown: number;
100
+ }
101
+ /**
102
+ * How a readiness stands, as counts. Pure and total: a host renders "3 of 4 found" from the stored
103
+ * fact without deciding what an absent readiness means, because `observed` says so. The parameter
104
+ * is the least a value has to carry to be summarised, so core `Readiness` and the wire shape both
105
+ * pass without naming a type between them.
106
+ */
107
+ export declare const summary: (readiness: {
108
+ readonly requirements: ReadonlyArray<{
109
+ readonly status: Storage.RequirementStatus;
110
+ }>;
111
+ } | null) => Summary;
84
112
  export interface PolicyShape {
85
113
  /** Delay before the next check, given time since the first pending observation. Default ladder: 15s, 1m, 5m, 30m. */
86
114
  readonly backoff: (pendingForMs: number) => number;
@@ -93,6 +121,47 @@ export declare const defaults: PolicyShape;
93
121
  declare const Policy_base: Context.Reference<PolicyShape>;
94
122
  export declare class Policy extends Policy_base {
95
123
  }
124
+ /** Why readiness was written: a DNS observation, or host evidence merged into the stored row. */
125
+ export type Cause = "observe" | "evidence";
126
+ export interface ReadinessChanged {
127
+ /** The tenant the row was written under, from the `Principal` the write ran as. */
128
+ readonly ownerId: string;
129
+ readonly domain: string;
130
+ readonly readiness: Readiness;
131
+ readonly cause: Cause;
132
+ }
133
+ export interface ObserverShape {
134
+ /**
135
+ * Called once per stored readiness, after the write. A host that projects readiness onto its own
136
+ * rows, wakes a durable job at `nextCheckAt`, or notifies a customer hangs it here instead of
137
+ * mirroring the fact at every call site.
138
+ *
139
+ * Readiness is stored per owner and domain, and an observer provided over `DomainKit.layer` is
140
+ * scoped to the layer rather than to one request, so a host that serves more than one tenant
141
+ * keys its projection by `ownerId` and `domain`: the same domain name can be attached in two
142
+ * tenants at once.
143
+ *
144
+ * Events for one domain are not ordered against each other: two observations that overlap both
145
+ * store, last write wins in `Storage`, and their callbacks can finish in either order. A
146
+ * projection compares `readiness.checkedAt`, which is the moment the row was written, and keeps
147
+ * the later one; `latest` remains the authority.
148
+ */
149
+ readonly readinessChanged: (event: ReadinessChanged) => Effect.Effect<void, unknown>;
150
+ }
151
+ declare const Observer_base: Context.Reference<ObserverShape>;
152
+ /**
153
+ * The host seam for "DomainKit wrote readiness". The default does nothing; provide one with
154
+ * `Effect.provideService(Verify.Observer, ...)` or `Layer.succeed(Verify.Observer, ...)` over
155
+ * `DomainKit.layer`, the same way `Policy` is overridden.
156
+ *
157
+ * It runs after `storage.readiness.put` returns, outside any transaction, because `Storage`
158
+ * exposes none. A failure or defect in the observer is logged and swallowed: the observation is
159
+ * already durable, and losing it because a projection failed would make the stored fact depend on
160
+ * the host's side effects. A host that needs the projection to be reliable enqueues durable work
161
+ * here rather than doing the work inline.
162
+ */
163
+ export declare class Observer extends Observer_base {
164
+ }
96
165
  /** A requirement is satisfied by an exact match; an exclusive one is contradicted by any same-set record. */
97
166
  export declare const statusAgainst: (record: DnsRecord.Model, observed: ReadonlyArray<DnsRecord.Observed>) => Storage.RequirementStatus;
98
167
  export declare const make: Effect.Effect<Interface, never, Storage.Service | Connect.Service | Resolver.Service>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "domainkit",
3
- "version": "0.13.0",
3
+ "version": "0.14.1",
4
4
  "description": "Build reviewable DNS plans for custom domains in TypeScript",
5
5
  "keywords": [
6
6
  "custom-domains",