@camox/api-contract 0.44.0 → 0.45.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/dist/analytics.d.ts +19 -0
- package/dist/analytics.js +18 -0
- package/dist/drafts.d.ts +82 -0
- package/dist/drafts.js +145 -0
- package/dist/icon-catalog.d.ts +7 -0
- package/dist/icon-catalog.js +48 -0
- package/dist/icons-BAxwOBBX.d.ts +19 -0
- package/dist/icons-Bk4igP2j.js +15 -0
- package/dist/ids.d.ts +26 -0
- package/dist/ids.js +40 -0
- package/dist/index.d.ts +12358 -8035
- package/dist/index.js +64 -96
- package/dist/projects.d.ts +28 -0
- package/dist/projects.js +50 -0
- package/dist/query-keys.d.ts +58 -42
- package/dist/query-keys.js +118 -32
- package/dist/threads.d.ts +277 -0
- package/dist/threads.js +263 -0
- package/package.json +53 -6
- package/src/analytics.ts +22 -0
- package/src/artifact.ts +38 -0
- package/src/drafts.ts +197 -0
- package/src/icon-catalog.ts +60 -0
- package/src/icons.ts +0 -57
- package/src/ids.ts +43 -0
- package/src/index.ts +5 -1
- package/src/projects.ts +67 -0
- package/src/query-keys.ts +64 -30
- package/src/reference-query.ts +48 -0
- package/src/threads.ts +327 -0
- package/dist/icons.d.ts +0 -20
- package/dist/icons.js +0 -72
- package/src/comments.ts +0 -33
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region src/analytics.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* A GA4 measurement ID: `G-` followed by uppercase letters and digits. Shared so the dashboard
|
|
5
|
+
* checks an ID by the API's own rule before saving it.
|
|
6
|
+
*/
|
|
7
|
+
export declare const ga4MeasurementIdSchema: z.ZodString;
|
|
8
|
+
/**
|
|
9
|
+
* A PostHog project API key: `phc_` followed by letters and digits. The prefix tells it apart from
|
|
10
|
+
* a personal API key, which is secret and must never reach a public page.
|
|
11
|
+
*/
|
|
12
|
+
export declare const posthogProjectApiKeySchema: z.ZodString;
|
|
13
|
+
/** The PostHog Cloud region a project lives in. */
|
|
14
|
+
export declare const posthogRegionSchema: z.ZodEnum<{
|
|
15
|
+
us: "us";
|
|
16
|
+
eu: "eu";
|
|
17
|
+
}>;
|
|
18
|
+
export type PosthogRegion = z.output<typeof posthogRegionSchema>;
|
|
19
|
+
//#endregion
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/analytics.ts
|
|
4
|
+
/**
|
|
5
|
+
* A GA4 measurement ID: `G-` followed by uppercase letters and digits. Shared so the dashboard
|
|
6
|
+
* checks an ID by the API's own rule before saving it.
|
|
7
|
+
*/
|
|
8
|
+
const ga4MeasurementIdSchema = /* @__PURE__ */ z.string().regex(/^G-[A-Z0-9]+$/, "Not a GA4 measurement ID");
|
|
9
|
+
/**
|
|
10
|
+
* A PostHog project API key: `phc_` followed by letters and digits. The prefix tells it apart from
|
|
11
|
+
* a personal API key, which is secret and must never reach a public page.
|
|
12
|
+
*/
|
|
13
|
+
const posthogProjectApiKeySchema = /* @__PURE__ */ z.string().regex(/^phc_[A-Za-z0-9]+$/, "Not a PostHog project API key");
|
|
14
|
+
/** The PostHog Cloud region a project lives in. */
|
|
15
|
+
const posthogRegionSchema = /* @__PURE__ */ z.enum(["us", "eu"]);
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
export { ga4MeasurementIdSchema, posthogProjectApiKeySchema, posthogRegionSchema };
|
package/dist/drafts.d.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
//#region src/drafts.d.ts
|
|
2
|
+
/** Request header naming the draft a request reads and writes (ADR 0011). Absent means Live. */
|
|
3
|
+
export declare const DRAFT_HEADER = "x-camox-draft";
|
|
4
|
+
/**
|
|
5
|
+
* Request header naming, by its tag, the locale a request reads and writes content in (ADR
|
|
6
|
+
* 0015). Absent means the project's default locale.
|
|
7
|
+
*/
|
|
8
|
+
export declare const LOCALE_HEADER = "x-camox-locale";
|
|
9
|
+
/**
|
|
10
|
+
* Request header asking the API to create the draft named by `DRAFT_HEADER` if it doesn't
|
|
11
|
+
* exist yet. Its value is `"1"`.
|
|
12
|
+
*/
|
|
13
|
+
export declare const DRAFT_CREATE_HEADER = "x-camox-draft-create";
|
|
14
|
+
/**
|
|
15
|
+
* The `x-camox-draft` value naming the caller's own development draft in the project a request
|
|
16
|
+
* acts on (ADR 0006, ADR 0011). Dev mode and the CLI always send it.
|
|
17
|
+
*/
|
|
18
|
+
export declare const DEVELOPMENT_DRAFT = "development";
|
|
19
|
+
/**
|
|
20
|
+
* oRPC error code for a request naming the development draft before dev mode created it: the
|
|
21
|
+
* first dev-mode sync after login does, so the site has to run locally once first.
|
|
22
|
+
*/
|
|
23
|
+
export declare const NO_DEVELOPMENT_DRAFT_ERROR = "NO_DEVELOPMENT_DRAFT";
|
|
24
|
+
/** URL search param carrying the current draft's id in the studio and the rendered site. */
|
|
25
|
+
export declare const DRAFT_SEARCH_PARAM = "camox-draft";
|
|
26
|
+
/** A regular draft is a named set of edits; a development draft backs a dev server. */
|
|
27
|
+
export type DraftKind = "regular" | "development";
|
|
28
|
+
/** How a regular draft ended. */
|
|
29
|
+
export type DraftOutcome = "published" | "discarded";
|
|
30
|
+
/** Who ended a draft, how and when, from its ended-drafts record (ADR 0009, ADR 0011). */
|
|
31
|
+
export type EndedDraft = {
|
|
32
|
+
draftId: string;
|
|
33
|
+
outcome: DraftOutcome;
|
|
34
|
+
endedBy: {
|
|
35
|
+
id: string;
|
|
36
|
+
name: string;
|
|
37
|
+
};
|
|
38
|
+
endedAt: number;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* The oRPC error code a request naming an ended draft fails with. Its `data` is an `EndedDraft`,
|
|
42
|
+
* so a page can render Live and say who published or discarded the draft.
|
|
43
|
+
*/
|
|
44
|
+
export declare const DRAFT_ENDED_ERROR_CODE = "DRAFT_ENDED";
|
|
45
|
+
/**
|
|
46
|
+
* oRPC error code for a publish whose token no longer matches Live: Live changed since the
|
|
47
|
+
* preview, so nothing was applied and the caller reviews the new preview.
|
|
48
|
+
*/
|
|
49
|
+
export declare const CONFLICTS_CHANGED_ERROR = "CONFLICTS_CHANGED";
|
|
50
|
+
/** oRPC error code for a publish refused because the draft still has blockers. */
|
|
51
|
+
export declare const PUBLISH_BLOCKED_ERROR = "PUBLISH_BLOCKED";
|
|
52
|
+
/**
|
|
53
|
+
* oRPC error code for a publish refused because the draft still has pending translations: every
|
|
54
|
+
* locale goes live together, unless the caller publishes anyway (ADR 0017).
|
|
55
|
+
*/
|
|
56
|
+
export declare const TRANSLATIONS_PENDING_ERROR = "TRANSLATIONS_PENDING";
|
|
57
|
+
/**
|
|
58
|
+
* Why the publish tool published nothing of a draft with changes, and returned a fresh preview to
|
|
59
|
+
* review again, by the error code of each: Live changed since the preview, the draft has blockers,
|
|
60
|
+
* or translations are still running.
|
|
61
|
+
*/
|
|
62
|
+
export declare const NOT_PUBLISHED_CODES: {
|
|
63
|
+
readonly conflictsChanged: "CONFLICTS_CHANGED";
|
|
64
|
+
readonly blocked: "PUBLISH_BLOCKED";
|
|
65
|
+
readonly translating: "TRANSLATIONS_PENDING";
|
|
66
|
+
};
|
|
67
|
+
export type NotPublishedReason = keyof typeof NOT_PUBLISHED_CODES;
|
|
68
|
+
/**
|
|
69
|
+
* Who Camox's own work is by: the creator of the drafts it opens to catch translations up, their
|
|
70
|
+
* publisher on Live, and who ended them. Shown as "Camox".
|
|
71
|
+
*/
|
|
72
|
+
export declare const CAMOX_ACTOR = "camox";
|
|
73
|
+
/** The name Camox's own work shows under. */
|
|
74
|
+
export declare const CAMOX_NAME = "Camox";
|
|
75
|
+
/**
|
|
76
|
+
* oRPC error code for a content write that names no draft. Live is read-only (ADR 0003): content
|
|
77
|
+
* changes reach it only by publishing a draft, or through a release.
|
|
78
|
+
*/
|
|
79
|
+
export declare const LIVE_READ_ONLY_ERROR = "LIVE_READ_ONLY";
|
|
80
|
+
/** Whether the procedure at `path` (`[router, procedure]`) writes content. */
|
|
81
|
+
export declare function isContentWrite(path: readonly string[]): boolean;
|
|
82
|
+
//#endregion
|
package/dist/drafts.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
//#region src/drafts.ts
|
|
2
|
+
/** Request header naming the draft a request reads and writes (ADR 0011). Absent means Live. */
|
|
3
|
+
const DRAFT_HEADER = "x-camox-draft";
|
|
4
|
+
/**
|
|
5
|
+
* Request header naming, by its tag, the locale a request reads and writes content in (ADR
|
|
6
|
+
* 0015). Absent means the project's default locale.
|
|
7
|
+
*/
|
|
8
|
+
const LOCALE_HEADER = "x-camox-locale";
|
|
9
|
+
/**
|
|
10
|
+
* Request header asking the API to create the draft named by `DRAFT_HEADER` if it doesn't
|
|
11
|
+
* exist yet. Its value is `"1"`.
|
|
12
|
+
*/
|
|
13
|
+
const DRAFT_CREATE_HEADER = "x-camox-draft-create";
|
|
14
|
+
/**
|
|
15
|
+
* The `x-camox-draft` value naming the caller's own development draft in the project a request
|
|
16
|
+
* acts on (ADR 0006, ADR 0011). Dev mode and the CLI always send it.
|
|
17
|
+
*/
|
|
18
|
+
const DEVELOPMENT_DRAFT = "development";
|
|
19
|
+
/**
|
|
20
|
+
* oRPC error code for a request naming the development draft before dev mode created it: the
|
|
21
|
+
* first dev-mode sync after login does, so the site has to run locally once first.
|
|
22
|
+
*/
|
|
23
|
+
const NO_DEVELOPMENT_DRAFT_ERROR = "NO_DEVELOPMENT_DRAFT";
|
|
24
|
+
/** URL search param carrying the current draft's id in the studio and the rendered site. */
|
|
25
|
+
const DRAFT_SEARCH_PARAM = "camox-draft";
|
|
26
|
+
/**
|
|
27
|
+
* The oRPC error code a request naming an ended draft fails with. Its `data` is an `EndedDraft`,
|
|
28
|
+
* so a page can render Live and say who published or discarded the draft.
|
|
29
|
+
*/
|
|
30
|
+
const DRAFT_ENDED_ERROR_CODE = "DRAFT_ENDED";
|
|
31
|
+
/**
|
|
32
|
+
* oRPC error code for a publish whose token no longer matches Live: Live changed since the
|
|
33
|
+
* preview, so nothing was applied and the caller reviews the new preview.
|
|
34
|
+
*/
|
|
35
|
+
const CONFLICTS_CHANGED_ERROR = "CONFLICTS_CHANGED";
|
|
36
|
+
/** oRPC error code for a publish refused because the draft still has blockers. */
|
|
37
|
+
const PUBLISH_BLOCKED_ERROR = "PUBLISH_BLOCKED";
|
|
38
|
+
/**
|
|
39
|
+
* oRPC error code for a publish refused because the draft still has pending translations: every
|
|
40
|
+
* locale goes live together, unless the caller publishes anyway (ADR 0017).
|
|
41
|
+
*/
|
|
42
|
+
const TRANSLATIONS_PENDING_ERROR = "TRANSLATIONS_PENDING";
|
|
43
|
+
/**
|
|
44
|
+
* Why the publish tool published nothing of a draft with changes, and returned a fresh preview to
|
|
45
|
+
* review again, by the error code of each: Live changed since the preview, the draft has blockers,
|
|
46
|
+
* or translations are still running.
|
|
47
|
+
*/
|
|
48
|
+
const NOT_PUBLISHED_CODES = {
|
|
49
|
+
conflictsChanged: CONFLICTS_CHANGED_ERROR,
|
|
50
|
+
blocked: PUBLISH_BLOCKED_ERROR,
|
|
51
|
+
translating: TRANSLATIONS_PENDING_ERROR
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Who Camox's own work is by: the creator of the drafts it opens to catch translations up, their
|
|
55
|
+
* publisher on Live, and who ended them. Shown as "Camox".
|
|
56
|
+
*/
|
|
57
|
+
const CAMOX_ACTOR = "camox";
|
|
58
|
+
/** The name Camox's own work shows under. */
|
|
59
|
+
const CAMOX_NAME = "Camox";
|
|
60
|
+
/**
|
|
61
|
+
* oRPC error code for a content write that names no draft. Live is read-only (ADR 0003): content
|
|
62
|
+
* changes reach it only by publishing a draft, or through a release.
|
|
63
|
+
*/
|
|
64
|
+
const LIVE_READ_ONLY_ERROR = "LIVE_READ_ONLY";
|
|
65
|
+
const CONTENT_WRITES = {
|
|
66
|
+
blocks: {
|
|
67
|
+
get: false,
|
|
68
|
+
getPageMarkdown: false,
|
|
69
|
+
getLayoutMarkdown: false,
|
|
70
|
+
getUsageCounts: false,
|
|
71
|
+
getPagesUsing: false,
|
|
72
|
+
getSyncedContent: false,
|
|
73
|
+
create: true,
|
|
74
|
+
updateContent: true,
|
|
75
|
+
updateSettings: true,
|
|
76
|
+
updatePosition: true,
|
|
77
|
+
delete: true,
|
|
78
|
+
deleteMany: true,
|
|
79
|
+
generateSummary: false,
|
|
80
|
+
duplicate: true
|
|
81
|
+
},
|
|
82
|
+
locales: {
|
|
83
|
+
list: false,
|
|
84
|
+
add: true,
|
|
85
|
+
remove: true,
|
|
86
|
+
setDefaultTag: false,
|
|
87
|
+
listMissing: false,
|
|
88
|
+
addBack: true
|
|
89
|
+
},
|
|
90
|
+
collectionDefinitions: {
|
|
91
|
+
list: false,
|
|
92
|
+
get: false,
|
|
93
|
+
listRecords: false,
|
|
94
|
+
getRecord: false,
|
|
95
|
+
getRecordUsageCount: false,
|
|
96
|
+
findRecordsByField: false,
|
|
97
|
+
listRecordPageValues: false,
|
|
98
|
+
recordMarkdown: false,
|
|
99
|
+
createRecord: true,
|
|
100
|
+
editRecord: true,
|
|
101
|
+
deleteRecord: true
|
|
102
|
+
},
|
|
103
|
+
files: {
|
|
104
|
+
list: false,
|
|
105
|
+
get: false,
|
|
106
|
+
getUsageCount: false,
|
|
107
|
+
setAlt: true,
|
|
108
|
+
setFilename: true,
|
|
109
|
+
delete: true,
|
|
110
|
+
deleteMany: true,
|
|
111
|
+
setAiMetadata: true,
|
|
112
|
+
generateMetadata: false
|
|
113
|
+
},
|
|
114
|
+
pages: {
|
|
115
|
+
getByPath: false,
|
|
116
|
+
getStructure: false,
|
|
117
|
+
list: false,
|
|
118
|
+
listBySlug: false,
|
|
119
|
+
get: false,
|
|
120
|
+
create: true,
|
|
121
|
+
update: true,
|
|
122
|
+
delete: true,
|
|
123
|
+
setSeo: true,
|
|
124
|
+
setLayout: true,
|
|
125
|
+
generateSeo: false
|
|
126
|
+
},
|
|
127
|
+
repeatableItems: {
|
|
128
|
+
get: false,
|
|
129
|
+
create: true,
|
|
130
|
+
updateContent: true,
|
|
131
|
+
updateSettings: true,
|
|
132
|
+
updatePosition: true,
|
|
133
|
+
duplicate: true,
|
|
134
|
+
generateSummary: false,
|
|
135
|
+
delete: true
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
/** Whether the procedure at `path` (`[router, procedure]`) writes content. */
|
|
139
|
+
function isContentWrite(path) {
|
|
140
|
+
if (path.length !== 2) return false;
|
|
141
|
+
return CONTENT_WRITES[path[0]]?.[path[1]] === true;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
//#endregion
|
|
145
|
+
export { CAMOX_ACTOR, CAMOX_NAME, CONFLICTS_CHANGED_ERROR, DEVELOPMENT_DRAFT, DRAFT_CREATE_HEADER, DRAFT_ENDED_ERROR_CODE, DRAFT_HEADER, DRAFT_SEARCH_PARAM, LIVE_READ_ONLY_ERROR, LOCALE_HEADER, NOT_PUBLISHED_CODES, NO_DEVELOPMENT_DRAFT_ERROR, PUBLISH_BLOCKED_ERROR, TRANSLATIONS_PENDING_ERROR, isContentWrite };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { n as IconSvgData } from "./icons-BAxwOBBX.js";
|
|
2
|
+
import { IconifyJSON } from "@iconify/types";
|
|
3
|
+
//#region src/icon-catalog.d.ts
|
|
4
|
+
export declare function loadIconCollection(prefix: string): Promise<IconifyJSON>;
|
|
5
|
+
export declare function iconCollectionIds(data: IconifyJSON): string[];
|
|
6
|
+
export declare function resolveIconSvg(data: IconifyJSON, id: string): IconSvgData;
|
|
7
|
+
//#endregion
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { t as ICON_CATALOG_VERSION } from "./icons-Bk4igP2j.js";
|
|
2
|
+
import { getIconData, iconToSVG } from "@iconify/utils";
|
|
3
|
+
|
|
4
|
+
//#region src/icon-catalog.ts
|
|
5
|
+
const collections = /* @__PURE__ */ new Map();
|
|
6
|
+
async function loadIconCollection(prefix) {
|
|
7
|
+
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(prefix)) throw new Error("Invalid icon collection");
|
|
8
|
+
const existing = collections.get(prefix);
|
|
9
|
+
if (existing) return existing;
|
|
10
|
+
const pending = (async () => {
|
|
11
|
+
const response = await fetch(`https://unpkg.com/@iconify/json@${ICON_CATALOG_VERSION}/json/${prefix}.json`, { signal: AbortSignal.timeout(3e4) });
|
|
12
|
+
if (!response.ok) throw new Error(`Unable to load icon collection ${prefix}`);
|
|
13
|
+
const data = await response.json();
|
|
14
|
+
if (data.prefix !== prefix || !data.icons || !data.info?.license) throw new Error("Invalid icon catalog or missing license");
|
|
15
|
+
return data;
|
|
16
|
+
})();
|
|
17
|
+
collections.set(prefix, pending);
|
|
18
|
+
if (collections.size > 8) collections.delete(collections.keys().next().value);
|
|
19
|
+
try {
|
|
20
|
+
return await pending;
|
|
21
|
+
} catch (error) {
|
|
22
|
+
collections.delete(prefix);
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function iconCollectionIds(data) {
|
|
27
|
+
return [...Object.keys(data.icons), ...Object.keys(data.aliases ?? {})].filter((name) => getIconData(data, name) !== null).sort().map((name) => `${data.prefix}:${name}`);
|
|
28
|
+
}
|
|
29
|
+
function resolveIconSvg(data, id) {
|
|
30
|
+
const [prefix, name, extra] = id.split(":");
|
|
31
|
+
if (prefix !== data.prefix || !name || extra !== void 0) throw new Error("Invalid icon ID");
|
|
32
|
+
const icon = getIconData(data, name);
|
|
33
|
+
if (!icon) throw new Error(`Unknown icon: ${id}`);
|
|
34
|
+
const svg = iconToSVG(icon);
|
|
35
|
+
return {
|
|
36
|
+
body: svg.body,
|
|
37
|
+
attributes: svg.attributes,
|
|
38
|
+
attribution: data.info ? {
|
|
39
|
+
collection: data.info.name,
|
|
40
|
+
author: data.info.author.name,
|
|
41
|
+
license: data.info.license.title,
|
|
42
|
+
url: data.info.license.url
|
|
43
|
+
} : void 0
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//#endregion
|
|
48
|
+
export { iconCollectionIds, loadIconCollection, resolveIconSvg };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/icons.d.ts
|
|
2
|
+
declare const ICON_CATALOG_VERSION = "2.2.532";
|
|
3
|
+
type IconSvgData = {
|
|
4
|
+
body: string;
|
|
5
|
+
attributes: Record<string, string>;
|
|
6
|
+
attribution?: {
|
|
7
|
+
collection: string;
|
|
8
|
+
author: string;
|
|
9
|
+
license: string;
|
|
10
|
+
url?: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
declare function scopeIconSvgIds(body: string, prefix: string): string;
|
|
14
|
+
declare function validateIconValue(value: unknown, schema: {
|
|
15
|
+
fieldType?: string;
|
|
16
|
+
enum?: unknown;
|
|
17
|
+
}): void;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { validateIconValue as i, IconSvgData as n, scopeIconSvgIds as r, ICON_CATALOG_VERSION as t };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/icons.ts
|
|
2
|
+
const ICON_CATALOG_VERSION = "2.2.532";
|
|
3
|
+
function scopeIconSvgIds(body, prefix) {
|
|
4
|
+
const ids = [...body.matchAll(/\sid="([^\s"]+)"/g)].map((match) => match[1]);
|
|
5
|
+
if (!ids.length) return body;
|
|
6
|
+
const pattern = ids.map((id) => id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
7
|
+
return body.replace(new RegExp(`([#;"])(${pattern})([")]|\\.[a-z])`, "g"), (_match, before, id, after) => `${before}${prefix}${id}${after}`);
|
|
8
|
+
}
|
|
9
|
+
function validateIconValue(value, schema) {
|
|
10
|
+
if (schema.fieldType !== "Icon") return;
|
|
11
|
+
if (typeof value !== "string" || !Array.isArray(schema.enum) || !schema.enum.includes(value)) throw new Error(`Invalid icon ID: ${String(value)}`);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
export { scopeIconSvgIds as n, validateIconValue as r, ICON_CATALOG_VERSION as t };
|
package/dist/ids.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region src/ids.d.ts
|
|
3
|
+
/** The id of a content entity: one UUIDv7, kept in Live and every draft (ADR 0004). */
|
|
4
|
+
export declare const uuidv7Schema: z.ZodUUID;
|
|
5
|
+
/**
|
|
6
|
+
* A Project ID: a UUIDv7 in lowercase only, the form the project's Worker is named by, so an
|
|
7
|
+
* uppercase one fails here rather than silently naming no project.
|
|
8
|
+
*/
|
|
9
|
+
export declare const projectIdSchema: z.ZodUUID;
|
|
10
|
+
/**
|
|
11
|
+
* `uuidv7Schema` as JSON Schema, for content schemas. Written out rather than derived, so site
|
|
12
|
+
* bundles, which need only this, leave zod out.
|
|
13
|
+
*/
|
|
14
|
+
export declare const uuidv7JsonSchema: {
|
|
15
|
+
type: string;
|
|
16
|
+
format: string;
|
|
17
|
+
pattern: string;
|
|
18
|
+
};
|
|
19
|
+
/** A text link to a page: this prefix, then the page's UUIDv7. */
|
|
20
|
+
export declare const PAGE_TEXT_LINK_PREFIX = "camox:page:";
|
|
21
|
+
/**
|
|
22
|
+
* Mints a UUIDv7 (RFC 9562): a 48-bit millisecond timestamp, then random bits.
|
|
23
|
+
* The server mints ids; clients mint one only for optimistic inserts.
|
|
24
|
+
*/
|
|
25
|
+
export declare function generateUuidv7(): string;
|
|
26
|
+
//#endregion
|
package/dist/ids.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/ids.ts
|
|
4
|
+
/** The id of a content entity: one UUIDv7, kept in Live and every draft (ADR 0004). */
|
|
5
|
+
const uuidv7Schema = /* @__PURE__ */ z.uuidv7();
|
|
6
|
+
/**
|
|
7
|
+
* A Project ID: a UUIDv7 in lowercase only, the form the project's Worker is named by, so an
|
|
8
|
+
* uppercase one fails here rather than silently naming no project.
|
|
9
|
+
*/
|
|
10
|
+
const projectIdSchema = /* @__PURE__ */ z.uuidv7().regex(/^[0-9a-f-]+$/, "A Project ID is a UUIDv7 in lowercase");
|
|
11
|
+
/**
|
|
12
|
+
* `uuidv7Schema` as JSON Schema, for content schemas. Written out rather than derived, so site
|
|
13
|
+
* bundles, which need only this, leave zod out.
|
|
14
|
+
*/
|
|
15
|
+
const uuidv7JsonSchema = {
|
|
16
|
+
type: "string",
|
|
17
|
+
format: "uuid",
|
|
18
|
+
pattern: "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"
|
|
19
|
+
};
|
|
20
|
+
/** A text link to a page: this prefix, then the page's UUIDv7. */
|
|
21
|
+
const PAGE_TEXT_LINK_PREFIX = "camox:page:";
|
|
22
|
+
/**
|
|
23
|
+
* Mints a UUIDv7 (RFC 9562): a 48-bit millisecond timestamp, then random bits.
|
|
24
|
+
* The server mints ids; clients mint one only for optimistic inserts.
|
|
25
|
+
*/
|
|
26
|
+
function generateUuidv7() {
|
|
27
|
+
const bytes = crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16));
|
|
28
|
+
let timestamp = Date.now();
|
|
29
|
+
for (let index = 5; index >= 0; index--) {
|
|
30
|
+
bytes[index] = timestamp % 256;
|
|
31
|
+
timestamp = Math.floor(timestamp / 256);
|
|
32
|
+
}
|
|
33
|
+
bytes[6] = bytes[6] & 15 | 112;
|
|
34
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
35
|
+
const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
36
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
export { PAGE_TEXT_LINK_PREFIX, generateUuidv7, projectIdSchema, uuidv7JsonSchema, uuidv7Schema };
|