@melite/estate-drafts 0.0.0-stage → 0.1.4-alpha

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/lib/spec.d.ts ADDED
@@ -0,0 +1,61 @@
1
+ import { z } from "zod";
2
+ /** One drafts-domain record: the doc plus the recency column the
3
+ * list arm orders by (the file-mtime equivalent — seconds). */
4
+ declare const DraftRecordSchema: z.ZodObject<{
5
+ updated_at: z.ZodNumber;
6
+ doc: z.ZodObject<{
7
+ draft_id: z.ZodString;
8
+ status: z.ZodString;
9
+ createdAt: z.ZodNumber;
10
+ completedAt: z.ZodUnion<readonly [z.ZodNumber, z.ZodNull]>;
11
+ intent: z.ZodString;
12
+ stages: z.ZodArray<z.ZodObject<{
13
+ id: z.ZodString;
14
+ }, z.core.$loose>>;
15
+ }, z.core.$loose>;
16
+ }, z.core.$strip>;
17
+ export type DraftRecord = z.infer<typeof DraftRecordSchema>;
18
+ /** The draft-id law (editor_runs.818-822 heritage): 1..96 chars,
19
+ * [A-Za-z0-9_-] ASCII only, path-safe. THE SSOT — the queue's
20
+ * submit gate and the drafts remote both test this one address
21
+ * (the queue re-exports it; gateway-core's copy is dead). */
22
+ export declare const DRAFT_ID_RE: RegExp;
23
+ /** The id's PATTERN and its bound, published so every gate that
24
+ * admits a draft id enforces the SAME rule (the census's H13: the
25
+ * queue's copy had no cap, so a long id passed one door and was
26
+ * refused by the next with a different voice). */
27
+ export declare const DRAFT_ID_PATTERN: RegExp;
28
+ export declare const DRAFT_ID_MAX_LEN = 96;
29
+ /** draft_id_ok (the doors' hand-loop drop-in): the law, one voice. */
30
+ export declare function draftIdOk(draftId: string): boolean;
31
+ /** The drafts domain (unit dir `drafts/`, version 1). */
32
+ export declare const draftsDomainSpec: {
33
+ name: string;
34
+ version: number;
35
+ layout: "per-record";
36
+ invalidRecords: "backup-and-skip";
37
+ global: {
38
+ schema: z.ZodNumber;
39
+ initial: number;
40
+ };
41
+ tables: {
42
+ docs: import("@deepseek-ai/dsh-storage-domain").DomainTableSpec<string, {
43
+ updated_at: number;
44
+ doc: {
45
+ [x: string]: unknown;
46
+ draft_id: string;
47
+ status: string;
48
+ createdAt: number;
49
+ completedAt: number | null;
50
+ intent: string;
51
+ stages: {
52
+ [x: string]: unknown;
53
+ id: string;
54
+ }[];
55
+ };
56
+ }>;
57
+ };
58
+ };
59
+ export type DraftsDomainSpec = typeof draftsDomainSpec;
60
+ export {};
61
+ //# sourceMappingURL=spec.d.ts.map
package/lib/spec.js ADDED
@@ -0,0 +1,57 @@
1
+
2
+ //
3
+ // The domain truth for draft docs: table `docs` keyed by draft id
4
+ // (DRAFT_ID_RE admits path-safe chars only, so the identity codec
5
+ // holds — no b64u here), one record per draft (large, sparse,
6
+ // individually disposable), schema-failing records backed up and
7
+ // skipped by the facility (`invalidRecords: 'backup-and-skip'`).
8
+ // The global slot is the one-time legacy-import marker: 0 until the
9
+ // legacy drafts tree has been imported, the import epoch (ms) after.
10
+ import { defineDomain, domainTable } from "@deepseek-ai/dsh-storage-domain";
11
+ import { z } from "zod";
12
+ /** One draft doc — the composer's shape: six contract keys plus
13
+ * caller extras verbatim. THE SERVE READ IS DELIBERATELY LOOSE
14
+ * (the write doors are strict; this read hands the composer's own
15
+ * extras back, pinned by bench-coverage's "extras ride the loose
16
+ * schema" row) — a looseObject needs no .passthrough() on top. */
17
+ const DraftDocSchema = z.looseObject({
18
+ draft_id: z.string(),
19
+ status: z.string(),
20
+ createdAt: z.number(),
21
+ completedAt: z.union([z.number(), z.null()]),
22
+ intent: z.string(),
23
+ stages: z.array(z.looseObject({ id: z.string() })),
24
+ });
25
+ /** One drafts-domain record: the doc plus the recency column the
26
+ * list arm orders by (the file-mtime equivalent — seconds). */
27
+ const DraftRecordSchema = z.object({
28
+ updated_at: z.number().int(),
29
+ doc: DraftDocSchema,
30
+ });
31
+ /** The draft-id law (editor_runs.818-822 heritage): 1..96 chars,
32
+ * [A-Za-z0-9_-] ASCII only, path-safe. THE SSOT — the queue's
33
+ * submit gate and the drafts remote both test this one address
34
+ * (the queue re-exports it; gateway-core's copy is dead). */
35
+ export const DRAFT_ID_RE = /^[A-Za-z0-9_-]{1,96}$/;
36
+ /** The id's PATTERN and its bound, published so every gate that
37
+ * admits a draft id enforces the SAME rule (the census's H13: the
38
+ * queue's copy had no cap, so a long id passed one door and was
39
+ * refused by the next with a different voice). */
40
+ export const DRAFT_ID_PATTERN = DRAFT_ID_RE;
41
+ export const DRAFT_ID_MAX_LEN = 96;
42
+ /** draft_id_ok (the doors' hand-loop drop-in): the law, one voice. */
43
+ export function draftIdOk(draftId) {
44
+ return DRAFT_ID_RE.test(draftId);
45
+ }
46
+ /** The drafts domain (unit dir `drafts/`, version 1). */
47
+ export const draftsDomainSpec = defineDomain({
48
+ name: "drafts",
49
+ version: 1,
50
+ layout: "per-record",
51
+ invalidRecords: "backup-and-skip",
52
+ global: { schema: z.number().int(), initial: 0 },
53
+ tables: {
54
+ docs: domainTable(DraftRecordSchema),
55
+ },
56
+ });
57
+ //# sourceMappingURL=spec.js.map
package/lib/store.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import type { Context } from "@deepseek-ai/cordis";
2
+ import type { Domain } from "@deepseek-ai/dsh-storage-domain";
3
+ import type { DraftsDomainSpec } from "./spec.js";
4
+ /** Env override for the unit-file root (an env seam, never a hardcode). */
5
+ export declare const STORAGE_ROOT_ENV: string;
6
+ /** The json backend's unit-file root: `<stateRoot>/storage`. */
7
+ export declare function resolveStorageRoot(): string;
8
+
9
+
10
+
11
+ export declare function openDraftsDomain(ctx: Context): Promise<Domain<DraftsDomainSpec>>;
12
+ //# sourceMappingURL=store.d.ts.map
package/lib/store.js ADDED
@@ -0,0 +1,106 @@
1
+ import { readFileSync, readdirSync, statSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { draftsDomainSpec } from "./spec.js";
4
+ /** Env override for the unit-file root (an env seam, never a hardcode). */
5
+ export const STORAGE_ROOT_ENV = "MELITE_STORAGE_ROOT";
6
+ /** Env seam for the state root the legacy drafts tree hangs under. */
7
+ const STATE_ROOT_ENV = "MELITE_STATE_ROOT";
8
+ /** The json backend's unit-file root: `<stateRoot>/storage`. */
9
+ export function resolveStorageRoot() {
10
+ const override = process.env[STORAGE_ROOT_ENV] ?? "";
11
+ if (override !== "")
12
+ return override;
13
+ const state = process.env[STATE_ROOT_ENV] ?? "data/runs";
14
+ return join(state, "storage");
15
+ }
16
+ /** The one-time legacy-drafts import (the pre-domain drafts tree →
17
+ * the drafts domain). Unparseable/non-object legacy files skip;
18
+ * schema-failing rows skip individually; the rest import. */
19
+ async function importLegacyDrafts(drafts) {
20
+ const marker = drafts.global;
21
+ if (marker.get() !== 0)
22
+ return;
23
+ const docs = drafts.table("docs");
24
+ const legacyDir = join(resolveStorageRoot(), "..", "drafts");
25
+ let names;
26
+ try {
27
+ names = readdirSync(legacyDir);
28
+ }
29
+ catch {
30
+ names = [];
31
+ }
32
+ for (const name of names) {
33
+ if (!name.endsWith(".json"))
34
+ continue;
35
+ const did = name.slice(0, -5);
36
+ if (docs.get(did) !== undefined)
37
+ continue;
38
+ let doc;
39
+ try {
40
+ doc = JSON.parse(readFileSync(join(legacyDir, name), "utf8"));
41
+ }
42
+ catch {
43
+ continue;
44
+ }
45
+ if (typeof doc !== "object" || doc === null || Array.isArray(doc))
46
+ continue;
47
+ const rec = doc;
48
+ if (typeof rec["draft_id"] !== "string")
49
+ rec["draft_id"] = did;
50
+ let updated = Math.floor(Date.now() / 1000);
51
+ try {
52
+ updated = Math.floor(statSync(join(legacyDir, name)).mtimeMs / 1000);
53
+ }
54
+ catch {
55
+ /* unstatable imports as now — ordering stays total */
56
+ }
57
+ try {
58
+ await docs.put(did, {
59
+ updated_at: updated,
60
+ doc: rec,
61
+ });
62
+ }
63
+ catch {
64
+ /* a schema-failing legacy row skips; the rest import */
65
+ }
66
+ }
67
+ await marker.set(Date.now());
68
+ }
69
+ let cached = new WeakMap();
70
+
71
+
72
+
73
+ export async function openDraftsDomain(ctx) {
74
+ const root = resolveStorageRoot();
75
+ // OPTIONAL-dependency probe per the tutorial's documented pattern
76
+ // (cordis-tutorial/03-services.md: "skip inject and probe at the
77
+ // use site" — property reads demand inject on loader-mounted
78
+ // fibers; ctx.get returns the active provider or undefined).
79
+ const facility = ctx.get("storageDomain");
80
+ if (facility === undefined || facility === null) {
81
+ throw new Error("[estate-drafts] storage domain facility not mounted (ctx.storageDomain)");
82
+ }
83
+ const hit = cached.get(facility);
84
+ if (hit !== undefined && hit.root === root)
85
+ return hit.ready;
86
+ // A foreign root never cross-writes another root's units.
87
+ if (hit !== undefined && hit.root !== root) {
88
+ throw new Error("[estate-drafts] storage serves the boot root only");
89
+ }
90
+ const ready = (async () => {
91
+ const drafts = await facility.open(draftsDomainSpec);
92
+ await importLegacyDrafts(drafts);
93
+ return drafts;
94
+ })();
95
+ cached.set(facility, { root, ready });
96
+ try {
97
+ return await ready;
98
+ }
99
+ catch (error) {
100
+ // Unconditional: one slot per facility exists at a time (a
101
+ // foreign root refuses above), so this rejection owns the slot.
102
+ cached.delete(facility);
103
+ throw error;
104
+ }
105
+ }
106
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1,3 @@
1
+ /* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */
2
+
3
+ export declare const TYPERT: unknown