@tier0/sdk-v2 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/NOTICE.md +7 -0
- package/README.md +201 -2
- package/dist/cjs/app-identity-contract.generated.d.ts +22 -0
- package/dist/cjs/app-identity-contract.generated.js +51 -0
- package/dist/cjs/app-identity-contract.generated.js.map +1 -0
- package/dist/cjs/capabilities.d.ts +54 -0
- package/dist/cjs/capabilities.js +134 -0
- package/dist/cjs/capabilities.js.map +1 -0
- package/dist/cjs/client.d.ts +604 -0
- package/dist/cjs/client.js +35 -0
- package/dist/cjs/client.js.map +1 -0
- package/dist/cjs/cloud-server.d.ts +31 -0
- package/dist/cjs/cloud-server.js +114 -0
- package/dist/cjs/cloud-server.js.map +1 -0
- package/dist/cjs/cloud-transport.d.ts +46 -0
- package/dist/cjs/cloud-transport.js +192 -0
- package/dist/cjs/cloud-transport.js.map +1 -0
- package/dist/cjs/controls.d.ts +93 -0
- package/dist/cjs/controls.js +169 -0
- package/dist/cjs/controls.js.map +1 -0
- package/dist/cjs/data/bootstrap.d.ts +66 -0
- package/dist/cjs/data/bootstrap.js +282 -0
- package/dist/cjs/data/bootstrap.js.map +1 -0
- package/dist/cjs/data/call.d.ts +16 -0
- package/dist/cjs/data/call.js +51 -0
- package/dist/cjs/data/call.js.map +1 -0
- package/dist/cjs/data/client.d.ts +92 -0
- package/dist/cjs/data/client.js +102 -0
- package/dist/cjs/data/client.js.map +1 -0
- package/dist/cjs/data/collection.d.ts +238 -0
- package/dist/cjs/data/collection.js +441 -0
- package/dist/cjs/data/collection.js.map +1 -0
- package/dist/cjs/data/context.d.ts +10 -0
- package/dist/cjs/data/context.js +39 -0
- package/dist/cjs/data/context.js.map +1 -0
- package/dist/cjs/data/declarations.d.ts +11 -0
- package/dist/cjs/data/declarations.js +18 -0
- package/dist/cjs/data/declarations.js.map +1 -0
- package/dist/cjs/data/define.d.ts +69 -0
- package/dist/cjs/data/define.js +31 -0
- package/dist/cjs/data/define.js.map +1 -0
- package/dist/cjs/data/error.d.ts +60 -0
- package/dist/cjs/data/error.js +184 -0
- package/dist/cjs/data/error.js.map +1 -0
- package/dist/cjs/data/index.d.ts +21 -0
- package/dist/cjs/data/index.js +43 -0
- package/dist/cjs/data/index.js.map +1 -0
- package/dist/cjs/data/schema.d.ts +82 -0
- package/dist/cjs/data/schema.js +607 -0
- package/dist/cjs/data/schema.js.map +1 -0
- package/dist/cjs/data/sort.d.ts +8 -0
- package/dist/cjs/data/sort.js +21 -0
- package/dist/cjs/data/sort.js.map +1 -0
- package/dist/cjs/files.d.ts +67 -0
- package/dist/cjs/files.js +119 -0
- package/dist/cjs/files.js.map +1 -0
- package/dist/cjs/framework-scope.d.ts +1 -0
- package/dist/cjs/framework-scope.js +14 -0
- package/dist/cjs/framework-scope.js.map +1 -0
- package/dist/cjs/index.d.ts +14 -0
- package/dist/cjs/index.js +33 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/mq/broker.d.ts +65 -0
- package/dist/cjs/mq/broker.js +115 -0
- package/dist/cjs/mq/broker.js.map +1 -0
- package/dist/cjs/mq/client.d.ts +37 -0
- package/dist/cjs/mq/client.js +321 -0
- package/dist/cjs/mq/client.js.map +1 -0
- package/dist/cjs/mq/index.d.ts +5 -0
- package/dist/cjs/mq/index.js +11 -0
- package/dist/cjs/mq/index.js.map +1 -0
- package/dist/cjs/mq/types.d.ts +48 -0
- package/dist/cjs/mq/types.js +3 -0
- package/dist/cjs/mq/types.js.map +1 -0
- package/dist/cjs/openapi/api.generated.d.ts +820 -0
- package/dist/cjs/openapi/api.generated.js +607 -0
- package/dist/cjs/openapi/api.generated.js.map +1 -0
- package/dist/cjs/openapi/client.d.ts +56 -0
- package/dist/cjs/openapi/client.js +219 -0
- package/dist/cjs/openapi/client.js.map +1 -0
- package/dist/cjs/openapi/codecs.generated.d.ts +2234 -0
- package/dist/cjs/openapi/codecs.generated.js +6 -0
- package/dist/cjs/openapi/codecs.generated.js.map +1 -0
- package/dist/cjs/openapi/index.d.ts +5 -0
- package/dist/cjs/openapi/index.js +12 -0
- package/dist/cjs/openapi/index.js.map +1 -0
- package/dist/cjs/openapi/types.generated.d.ts +3227 -0
- package/dist/cjs/openapi/types.generated.js +3 -0
- package/dist/cjs/openapi/types.generated.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/react.d.ts +9 -0
- package/dist/cjs/react.js +16 -0
- package/dist/cjs/react.js.map +1 -0
- package/dist/cjs/runtime-context.d.ts +9 -0
- package/dist/cjs/runtime-context.js +25 -0
- package/dist/cjs/runtime-context.js.map +1 -0
- package/dist/cjs/runtime-env.d.ts +1 -0
- package/dist/cjs/runtime-env.js +18 -0
- package/dist/cjs/runtime-env.js.map +1 -0
- package/dist/cjs/source.d.ts +39 -0
- package/dist/cjs/source.js +29 -0
- package/dist/cjs/source.js.map +1 -0
- package/dist/cjs/stream.d.ts +40 -0
- package/dist/cjs/stream.js +33 -0
- package/dist/cjs/stream.js.map +1 -0
- package/dist/cjs/uns-v2/client.d.ts +54 -0
- package/dist/cjs/uns-v2/client.js +177 -0
- package/dist/cjs/uns-v2/client.js.map +1 -0
- package/dist/cjs/uns-v2/codec.d.ts +11 -0
- package/dist/cjs/uns-v2/codec.js +290 -0
- package/dist/cjs/uns-v2/codec.js.map +1 -0
- package/dist/cjs/uns-v2/data-client.d.ts +10 -0
- package/dist/cjs/uns-v2/data-client.js +18 -0
- package/dist/cjs/uns-v2/data-client.js.map +1 -0
- package/dist/cjs/uns-v2/generated.d.ts +15551 -0
- package/dist/cjs/uns-v2/generated.js +139 -0
- package/dist/cjs/uns-v2/generated.js.map +1 -0
- package/dist/cjs/uns-v2/index.d.ts +5 -0
- package/dist/cjs/uns-v2/index.js +24 -0
- package/dist/cjs/uns-v2/index.js.map +1 -0
- package/dist/cjs/vue.d.ts +9 -0
- package/dist/cjs/vue.js +39 -0
- package/dist/cjs/vue.js.map +1 -0
- package/dist/esm/app-identity-contract.generated.d.ts +22 -0
- package/dist/esm/app-identity-contract.generated.js +48 -0
- package/dist/esm/app-identity-contract.generated.js.map +1 -0
- package/dist/esm/capabilities.d.ts +54 -0
- package/dist/esm/capabilities.js +129 -0
- package/dist/esm/capabilities.js.map +1 -0
- package/dist/esm/client.d.ts +604 -0
- package/dist/esm/client.js +32 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/cloud-server.d.ts +31 -0
- package/dist/esm/cloud-server.js +109 -0
- package/dist/esm/cloud-server.js.map +1 -0
- package/dist/esm/cloud-transport.d.ts +46 -0
- package/dist/esm/cloud-transport.js +187 -0
- package/dist/esm/cloud-transport.js.map +1 -0
- package/dist/esm/controls.d.ts +93 -0
- package/dist/esm/controls.js +163 -0
- package/dist/esm/controls.js.map +1 -0
- package/dist/esm/data/bootstrap.d.ts +66 -0
- package/dist/esm/data/bootstrap.js +277 -0
- package/dist/esm/data/bootstrap.js.map +1 -0
- package/dist/esm/data/call.d.ts +16 -0
- package/dist/esm/data/call.js +47 -0
- package/dist/esm/data/call.js.map +1 -0
- package/dist/esm/data/client.d.ts +92 -0
- package/dist/esm/data/client.js +99 -0
- package/dist/esm/data/client.js.map +1 -0
- package/dist/esm/data/collection.d.ts +238 -0
- package/dist/esm/data/collection.js +434 -0
- package/dist/esm/data/collection.js.map +1 -0
- package/dist/esm/data/context.d.ts +10 -0
- package/dist/esm/data/context.js +34 -0
- package/dist/esm/data/context.js.map +1 -0
- package/dist/esm/data/declarations.d.ts +11 -0
- package/dist/esm/data/declarations.js +10 -0
- package/dist/esm/data/declarations.js.map +1 -0
- package/dist/esm/data/define.d.ts +69 -0
- package/dist/esm/data/define.js +27 -0
- package/dist/esm/data/define.js.map +1 -0
- package/dist/esm/data/error.d.ts +60 -0
- package/dist/esm/data/error.js +178 -0
- package/dist/esm/data/error.js.map +1 -0
- package/dist/esm/data/index.d.ts +21 -0
- package/dist/esm/data/index.js +18 -0
- package/dist/esm/data/index.js.map +1 -0
- package/dist/esm/data/schema.d.ts +82 -0
- package/dist/esm/data/schema.js +596 -0
- package/dist/esm/data/schema.js.map +1 -0
- package/dist/esm/data/sort.d.ts +8 -0
- package/dist/esm/data/sort.js +18 -0
- package/dist/esm/data/sort.js.map +1 -0
- package/dist/esm/files.d.ts +67 -0
- package/dist/esm/files.js +113 -0
- package/dist/esm/files.js.map +1 -0
- package/dist/esm/framework-scope.d.ts +1 -0
- package/dist/esm/framework-scope.js +11 -0
- package/dist/esm/framework-scope.js.map +1 -0
- package/dist/esm/index.d.ts +14 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/mq/broker.d.ts +65 -0
- package/dist/esm/mq/broker.js +109 -0
- package/dist/esm/mq/broker.js.map +1 -0
- package/dist/esm/mq/client.d.ts +37 -0
- package/dist/esm/mq/client.js +314 -0
- package/dist/esm/mq/client.js.map +1 -0
- package/dist/esm/mq/index.d.ts +5 -0
- package/dist/esm/mq/index.js +3 -0
- package/dist/esm/mq/index.js.map +1 -0
- package/dist/esm/mq/types.d.ts +48 -0
- package/dist/esm/mq/types.js +2 -0
- package/dist/esm/mq/types.js.map +1 -0
- package/dist/esm/openapi/api.generated.d.ts +820 -0
- package/dist/esm/openapi/api.generated.js +603 -0
- package/dist/esm/openapi/api.generated.js.map +1 -0
- package/dist/esm/openapi/client.d.ts +56 -0
- package/dist/esm/openapi/client.js +210 -0
- package/dist/esm/openapi/client.js.map +1 -0
- package/dist/esm/openapi/codecs.generated.d.ts +2234 -0
- package/dist/esm/openapi/codecs.generated.js +3 -0
- package/dist/esm/openapi/codecs.generated.js.map +1 -0
- package/dist/esm/openapi/index.d.ts +5 -0
- package/dist/esm/openapi/index.js +3 -0
- package/dist/esm/openapi/index.js.map +1 -0
- package/dist/esm/openapi/types.generated.d.ts +3227 -0
- package/dist/esm/openapi/types.generated.js +2 -0
- package/dist/esm/openapi/types.generated.js.map +1 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/react.d.ts +9 -0
- package/dist/esm/react.js +12 -0
- package/dist/esm/react.js.map +1 -0
- package/dist/esm/runtime-context.d.ts +9 -0
- package/dist/esm/runtime-context.js +22 -0
- package/dist/esm/runtime-context.js.map +1 -0
- package/dist/esm/runtime-env.d.ts +1 -0
- package/dist/esm/runtime-env.js +15 -0
- package/dist/esm/runtime-env.js.map +1 -0
- package/dist/esm/source.d.ts +39 -0
- package/dist/esm/source.js +25 -0
- package/dist/esm/source.js.map +1 -0
- package/dist/esm/stream.d.ts +40 -0
- package/dist/esm/stream.js +29 -0
- package/dist/esm/stream.js.map +1 -0
- package/dist/esm/uns-v2/client.d.ts +54 -0
- package/dist/esm/uns-v2/client.js +170 -0
- package/dist/esm/uns-v2/client.js.map +1 -0
- package/dist/esm/uns-v2/codec.d.ts +11 -0
- package/dist/esm/uns-v2/codec.js +284 -0
- package/dist/esm/uns-v2/codec.js.map +1 -0
- package/dist/esm/uns-v2/data-client.d.ts +10 -0
- package/dist/esm/uns-v2/data-client.js +14 -0
- package/dist/esm/uns-v2/data-client.js.map +1 -0
- package/dist/esm/uns-v2/generated.d.ts +15551 -0
- package/dist/esm/uns-v2/generated.js +136 -0
- package/dist/esm/uns-v2/generated.js.map +1 -0
- package/dist/esm/uns-v2/index.d.ts +5 -0
- package/dist/esm/uns-v2/index.js +5 -0
- package/dist/esm/uns-v2/index.js.map +1 -0
- package/dist/esm/vue.d.ts +9 -0
- package/dist/esm/vue.js +36 -0
- package/dist/esm/vue.js.map +1 -0
- package/docs/acceptance-2026-10-22.md +88 -0
- package/package.json +242 -4
- package/skills/tier0-sdk-v2/SKILL.md +66 -0
- package/skills/tier0-sdk-v2/references/integration.md +72 -0
- package/skills/tier0-sdk-v2-agent/SKILL.md +73 -0
- package/skills/tier0-sdk-v2-agent/references/results.md +45 -0
- package/skills/tier0-sdk-v2-controls/SKILL.md +63 -0
- package/skills/tier0-sdk-v2-data/SKILL.md +57 -0
- package/skills/tier0-sdk-v2-data/references/consistency.md +70 -0
- package/skills/tier0-sdk-v2-data/references/errors.md +69 -0
- package/skills/tier0-sdk-v2-data/references/modeling.md +77 -0
- package/skills/tier0-sdk-v2-data/references/read-write.md +72 -0
- package/skills/tier0-sdk-v2-data/references/schema-evolution.md +36 -0
- package/skills/tier0-sdk-v2-files/SKILL.md +85 -0
- package/skills/tier0-sdk-v2-files/references/delete.md +22 -0
- package/skills/tier0-sdk-v2-files/references/download.md +49 -0
- package/skills/tier0-sdk-v2-files/references/multipart.md +42 -0
- package/skills/tier0-sdk-v2-files/references/upload.md +27 -0
- package/skills/tier0-sdk-v2-files/references/url.md +22 -0
- package/skills/tier0-sdk-v2-members/SKILL.md +56 -0
- package/skills/tier0-sdk-v2-members/references/app-members.md +41 -0
- package/skills/tier0-sdk-v2-members/references/platform-members.md +56 -0
- package/skills/tier0-sdk-v2-mq/SKILL.md +78 -0
- package/skills/tier0-sdk-v2-mq/references/quickstart.md +69 -0
- package/skills/tier0-sdk-v2-notifications/SKILL.md +42 -0
- package/skills/tier0-sdk-v2-notifications/references/get.md +34 -0
- package/skills/tier0-sdk-v2-notifications/references/send.md +72 -0
- package/skills/tier0-sdk-v2-source/SKILL.md +38 -0
- package/skills/tier0-sdk-v2-source/references/changes.md +40 -0
- package/skills/tier0-sdk-v2-source/references/create.md +63 -0
- package/skills/tier0-sdk-v2-source/references/delete.md +47 -0
- package/skills/tier0-sdk-v2-source/references/protocols.md +36 -0
- package/skills/tier0-sdk-v2-source/references/read.md +34 -0
- package/skills/tier0-sdk-v2-source/references/state.md +37 -0
- package/skills/tier0-sdk-v2-source/references/update.md +61 -0
- package/skills/tier0-sdk-v2-stream/SKILL.md +43 -0
- package/skills/tier0-sdk-v2-stream/references/create.md +55 -0
- package/skills/tier0-sdk-v2-stream/references/delete.md +35 -0
- package/skills/tier0-sdk-v2-stream/references/deploy.md +63 -0
- package/skills/tier0-sdk-v2-stream/references/lifecycle.md +25 -0
- package/skills/tier0-sdk-v2-stream/references/read.md +35 -0
- package/skills/tier0-sdk-v2-stream/references/update.md +35 -0
- package/skills/tier0-sdk-v2-system/SKILL.md +64 -0
- package/skills/tier0-sdk-v2-system/references/info.md +23 -0
- package/skills/tier0-sdk-v2-system/references/whoami.md +21 -0
- package/skills/tier0-sdk-v2-uns/SKILL.md +53 -0
- package/skills/tier0-sdk-v2-uns/references/create.md +85 -0
- package/skills/tier0-sdk-v2-uns/references/data-workflows.md +73 -0
- package/skills/tier0-sdk-v2-uns/references/delete.md +69 -0
- package/skills/tier0-sdk-v2-uns/references/namespace.md +75 -0
- package/skills/tier0-sdk-v2-uns/references/read.md +32 -0
- package/skills/tier0-sdk-v2-uns/references/restore.md +41 -0
- package/skills/tier0-sdk-v2-uns/references/update.md +86 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collection declarations — the single source of truth for App data.
|
|
3
|
+
*
|
|
4
|
+
* An App declares every collection with `defineCollection(...)` and passes the
|
|
5
|
+
* list to `createDataClient({ collections })`. The client ensures that list in
|
|
6
|
+
* one batch on first data access: a missing collection is created, a
|
|
7
|
+
* declaration wider than storage widens it, and nothing is ever narrowed.
|
|
8
|
+
*
|
|
9
|
+
* This module is pure (Zod types only) so declarations, API input schemas and
|
|
10
|
+
* build-time checks can import it without pulling in the runtime client.
|
|
11
|
+
*/
|
|
12
|
+
import type { z } from 'zod';
|
|
13
|
+
/** Collection alias: unique per App, case-insensitive. */
|
|
14
|
+
export declare const ALIAS_PATTERN: RegExp;
|
|
15
|
+
/** UNS: one ensure takes 1–64 declarations, and an App owns at most 64 collections. */
|
|
16
|
+
export declare const MAX_COLLECTIONS = 64;
|
|
17
|
+
/** UNS: collection description length in characters. */
|
|
18
|
+
export declare const MAX_DESCRIPTION_LENGTH = 512;
|
|
19
|
+
/** Seeds are inserted in atomic chunks of 200 during the first request; keep them a baseline, not a data import. */
|
|
20
|
+
export declare const MAX_SEED_DOCUMENTS = 1000;
|
|
21
|
+
/** Same shape as UNS `collectionCreate` indexes, limited to record indexes. */
|
|
22
|
+
export interface IndexSpec {
|
|
23
|
+
/** Business field path without `data.`, e.g. `code` or `customer.id`. */
|
|
24
|
+
path?: string;
|
|
25
|
+
/** Compound index, at most 3 paths. Mutually exclusive with `path`. */
|
|
26
|
+
paths?: string[];
|
|
27
|
+
unique?: boolean;
|
|
28
|
+
/** `btree` (default) or `gin` for one object/array path; GIN cannot be unique. */
|
|
29
|
+
kind?: 'btree' | 'gin';
|
|
30
|
+
}
|
|
31
|
+
/** System metadata of a stored record. Times are Unix milliseconds. */
|
|
32
|
+
export interface RecordMeta {
|
|
33
|
+
revision: number;
|
|
34
|
+
createdAt: number;
|
|
35
|
+
updatedAt: number;
|
|
36
|
+
}
|
|
37
|
+
export type CollectionSchema = z.ZodObject;
|
|
38
|
+
/** A seed document: a full record plus the fixed `_id` it is inserted with. */
|
|
39
|
+
export type SeedDoc<S extends CollectionSchema> = z.input<S> & {
|
|
40
|
+
_id: string;
|
|
41
|
+
};
|
|
42
|
+
export interface CollectionDefinition<S extends CollectionSchema = CollectionSchema> {
|
|
43
|
+
readonly alias: string;
|
|
44
|
+
/** Zod 4 object schema of the record body (no `_id` / `_meta`). */
|
|
45
|
+
readonly schema: S;
|
|
46
|
+
readonly indexes: readonly IndexSpec[];
|
|
47
|
+
readonly description?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Baseline records, written only when ensure reports this collection as
|
|
50
|
+
* `created`. Never re-applied to an existing collection.
|
|
51
|
+
*/
|
|
52
|
+
readonly seed?: readonly SeedDoc<S>[];
|
|
53
|
+
}
|
|
54
|
+
/** A stored record as services read it: `{ _id, ...fields, _meta }`. */
|
|
55
|
+
export type Doc<C extends CollectionDefinition> = z.output<C['schema']> & {
|
|
56
|
+
_id: string;
|
|
57
|
+
_meta: RecordMeta;
|
|
58
|
+
};
|
|
59
|
+
/** A record to insert: the schema input plus an optional caller-chosen `_id`. */
|
|
60
|
+
export type NewDoc<C extends CollectionDefinition> = z.input<C['schema']> & {
|
|
61
|
+
_id?: string;
|
|
62
|
+
};
|
|
63
|
+
export declare function defineCollection<S extends CollectionSchema>(definition: {
|
|
64
|
+
alias: string;
|
|
65
|
+
schema: S;
|
|
66
|
+
indexes?: IndexSpec[];
|
|
67
|
+
description?: string;
|
|
68
|
+
seed?: SeedDoc<S>[];
|
|
69
|
+
}): CollectionDefinition<S>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Collection alias: unique per App, case-insensitive. */
|
|
2
|
+
export const ALIAS_PATTERN = /^[A-Za-z][A-Za-z0-9_-]{0,62}$/;
|
|
3
|
+
/** UNS: one ensure takes 1–64 declarations, and an App owns at most 64 collections. */
|
|
4
|
+
export const MAX_COLLECTIONS = 64;
|
|
5
|
+
/** UNS: collection description length in characters. */
|
|
6
|
+
export const MAX_DESCRIPTION_LENGTH = 512;
|
|
7
|
+
/** Seeds are inserted in atomic chunks of 200 during the first request; keep them a baseline, not a data import. */
|
|
8
|
+
export const MAX_SEED_DOCUMENTS = 1000;
|
|
9
|
+
export function defineCollection(definition) {
|
|
10
|
+
if (!ALIAS_PATTERN.test(definition.alias)) {
|
|
11
|
+
throw new Error(`Collection alias "${definition.alias}" must match ${ALIAS_PATTERN} (letters, digits, "_" or "-", starting with a letter).`);
|
|
12
|
+
}
|
|
13
|
+
if (definition.description && [...definition.description].length > MAX_DESCRIPTION_LENGTH) {
|
|
14
|
+
throw new Error(`Collection "${definition.alias}": description is longer than ${MAX_DESCRIPTION_LENGTH} characters.`);
|
|
15
|
+
}
|
|
16
|
+
if (definition.seed && definition.seed.length > MAX_SEED_DOCUMENTS) {
|
|
17
|
+
throw new Error(`Collection "${definition.alias}": at most ${MAX_SEED_DOCUMENTS} seed documents (got ${definition.seed.length}). Seeds are a baseline written on creation, not a bulk import.`);
|
|
18
|
+
}
|
|
19
|
+
return Object.freeze({
|
|
20
|
+
alias: definition.alias,
|
|
21
|
+
schema: definition.schema,
|
|
22
|
+
indexes: Object.freeze([...(definition.indexes ?? [])]),
|
|
23
|
+
...(definition.description ? { description: definition.description } : {}),
|
|
24
|
+
...(definition.seed ? { seed: Object.freeze([...definition.seed]) } : {}),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=define.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define.js","sourceRoot":"","sources":["../../../src/data/define.ts"],"names":[],"mappings":"AAaA,0DAA0D;AAC1D,MAAM,CAAC,MAAM,aAAa,GAAG,+BAA+B,CAAC;AAC7D,uFAAuF;AACvF,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAC;AAClC,wDAAwD;AACxD,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAC1C,oHAAoH;AACpH,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAiDvC,MAAM,UAAU,gBAAgB,CAA6B,UAM5D;IACC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CACb,qBAAqB,UAAU,CAAC,KAAK,gBAAgB,aAAa,yDAAyD,CAC5H,CAAC;IACJ,CAAC;IACD,IAAI,UAAU,CAAC,WAAW,IAAI,CAAC,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC,MAAM,GAAG,sBAAsB,EAAE,CAAC;QAC1F,MAAM,IAAI,KAAK,CAAC,eAAe,UAAU,CAAC,KAAK,iCAAiC,sBAAsB,cAAc,CAAC,CAAC;IACxH,CAAC;IACD,IAAI,UAAU,CAAC,IAAI,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,GAAG,kBAAkB,EAAE,CAAC;QACnE,MAAM,IAAI,KAAK,CACb,eAAe,UAAU,CAAC,KAAK,cAAc,kBAAkB,wBAAwB,UAAU,CAAC,IAAI,CAAC,MAAM,iEAAiE,CAC/K,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,KAAK,EAAE,UAAU,CAAC,KAAK;QACvB,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC;QACvD,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1E,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1E,CAAC,CAAC;AACL,CAAC","sourcesContent":["/**\n * Collection declarations — the single source of truth for App data.\n *\n * An App declares every collection with `defineCollection(...)` and passes the\n * list to `createDataClient({ collections })`. The client ensures that list in\n * one batch on first data access: a missing collection is created, a\n * declaration wider than storage widens it, and nothing is ever narrowed.\n *\n * This module is pure (Zod types only) so declarations, API input schemas and\n * build-time checks can import it without pulling in the runtime client.\n */\nimport type { z } from 'zod';\n\n/** Collection alias: unique per App, case-insensitive. */\nexport const ALIAS_PATTERN = /^[A-Za-z][A-Za-z0-9_-]{0,62}$/;\n/** UNS: one ensure takes 1–64 declarations, and an App owns at most 64 collections. */\nexport const MAX_COLLECTIONS = 64;\n/** UNS: collection description length in characters. */\nexport const MAX_DESCRIPTION_LENGTH = 512;\n/** Seeds are inserted in atomic chunks of 200 during the first request; keep them a baseline, not a data import. */\nexport const MAX_SEED_DOCUMENTS = 1000;\n\n/** Same shape as UNS `collectionCreate` indexes, limited to record indexes. */\nexport interface IndexSpec {\n /** Business field path without `data.`, e.g. `code` or `customer.id`. */\n path?: string;\n /** Compound index, at most 3 paths. Mutually exclusive with `path`. */\n paths?: string[];\n unique?: boolean;\n /** `btree` (default) or `gin` for one object/array path; GIN cannot be unique. */\n kind?: 'btree' | 'gin';\n}\n\n/** System metadata of a stored record. Times are Unix milliseconds. */\nexport interface RecordMeta {\n revision: number;\n createdAt: number;\n updatedAt: number;\n}\n\nexport type CollectionSchema = z.ZodObject;\n\n/** A seed document: a full record plus the fixed `_id` it is inserted with. */\nexport type SeedDoc<S extends CollectionSchema> = z.input<S> & { _id: string };\n\nexport interface CollectionDefinition<S extends CollectionSchema = CollectionSchema> {\n readonly alias: string;\n /** Zod 4 object schema of the record body (no `_id` / `_meta`). */\n readonly schema: S;\n readonly indexes: readonly IndexSpec[];\n readonly description?: string;\n /**\n * Baseline records, written only when ensure reports this collection as\n * `created`. Never re-applied to an existing collection.\n */\n readonly seed?: readonly SeedDoc<S>[];\n}\n\n/** A stored record as services read it: `{ _id, ...fields, _meta }`. */\nexport type Doc<C extends CollectionDefinition> = z.output<C['schema']> & {\n _id: string;\n _meta: RecordMeta;\n};\n\n/** A record to insert: the schema input plus an optional caller-chosen `_id`. */\nexport type NewDoc<C extends CollectionDefinition> = z.input<C['schema']> & {\n _id?: string;\n};\n\nexport function defineCollection<S extends CollectionSchema>(definition: {\n alias: string;\n schema: S;\n indexes?: IndexSpec[];\n description?: string;\n seed?: SeedDoc<S>[];\n}): CollectionDefinition<S> {\n if (!ALIAS_PATTERN.test(definition.alias)) {\n throw new Error(\n `Collection alias \"${definition.alias}\" must match ${ALIAS_PATTERN} (letters, digits, \"_\" or \"-\", starting with a letter).`,\n );\n }\n if (definition.description && [...definition.description].length > MAX_DESCRIPTION_LENGTH) {\n throw new Error(`Collection \"${definition.alias}\": description is longer than ${MAX_DESCRIPTION_LENGTH} characters.`);\n }\n if (definition.seed && definition.seed.length > MAX_SEED_DOCUMENTS) {\n throw new Error(\n `Collection \"${definition.alias}\": at most ${MAX_SEED_DOCUMENTS} seed documents (got ${definition.seed.length}). Seeds are a baseline written on creation, not a bulk import.`,\n );\n }\n return Object.freeze({\n alias: definition.alias,\n schema: definition.schema,\n indexes: Object.freeze([...(definition.indexes ?? [])]),\n ...(definition.description ? { description: definition.description } : {}),\n ...(definition.seed ? { seed: Object.freeze([...definition.seed]) } : {}),\n });\n}\n"]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime failures of a data call, missing credentials included, are a
|
|
3
|
+
* `DataError`. The SDK's UNS client does the HTTP exchange; its `UnsV2Error`
|
|
4
|
+
* (kept as `cause`) is translated here, and the data layer raises its own codes
|
|
5
|
+
* (BATCH_LIMIT_EXCEEDED, WRITE_ERRORS, ...). `status` is the HTTP status the App
|
|
6
|
+
* should answer its own caller with. Writes that fail validation throw
|
|
7
|
+
* `ZodError`; programming or platform errors, such as invalid client options or
|
|
8
|
+
* a malformed data subject from the gateway, throw `TypeError`.
|
|
9
|
+
*/
|
|
10
|
+
import { type UnsV2Error } from '../uns-v2/client.js';
|
|
11
|
+
/**
|
|
12
|
+
* Stable `data.reason` codes UNS adds when it refuses App data access; the
|
|
13
|
+
* top-level code stays FORBIDDEN / NOT_FOUND. Only whole-request errors carry
|
|
14
|
+
* them, never per-item results of a batch or transaction.
|
|
15
|
+
*/
|
|
16
|
+
export declare const ACCESS_REASONS: {
|
|
17
|
+
/** 403: the collection exists, but this App's grant does not cover it or the operation. */
|
|
18
|
+
readonly notGranted: "COLLECTION_NOT_GRANTED";
|
|
19
|
+
/** 403 or 404: the collection is gone (hard-deleted or archived). */
|
|
20
|
+
readonly notFound: "COLLECTION_NOT_FOUND";
|
|
21
|
+
/** 403: the grant covers the operation, the App key lacks `data.missingPermission`. */
|
|
22
|
+
readonly permissionMissing: "APP_PERMISSION_MISSING";
|
|
23
|
+
};
|
|
24
|
+
export declare class DataError extends Error {
|
|
25
|
+
/** HTTP status the App should answer with (see `appStatus`). */
|
|
26
|
+
readonly status: number;
|
|
27
|
+
/** UNS error code, e.g. `DUPLICATE_KEY`, or a data-layer code. */
|
|
28
|
+
readonly code: string;
|
|
29
|
+
/** Stable `data.reason` code, e.g. `COLLECTION_NOT_FOUND` (see ACCESS_REASONS). */
|
|
30
|
+
readonly reason?: string;
|
|
31
|
+
/** HTTP status UNS answered with; 0 when no response arrived. */
|
|
32
|
+
readonly upstreamStatus: number;
|
|
33
|
+
readonly requestId?: string;
|
|
34
|
+
readonly retryable: boolean;
|
|
35
|
+
/** A write may have reached UNS: reconcile before replaying it with a new idempotency key. */
|
|
36
|
+
readonly outcomeUnknown: boolean;
|
|
37
|
+
/** The `data` object of the UNS error envelope, or data-layer details. */
|
|
38
|
+
readonly details: Record<string, unknown>;
|
|
39
|
+
constructor(init: {
|
|
40
|
+
message: string;
|
|
41
|
+
status: number;
|
|
42
|
+
code: string;
|
|
43
|
+
reason?: string;
|
|
44
|
+
upstreamStatus?: number;
|
|
45
|
+
requestId?: string;
|
|
46
|
+
retryable?: boolean;
|
|
47
|
+
outcomeUnknown?: boolean;
|
|
48
|
+
details?: Record<string, unknown>;
|
|
49
|
+
cause?: unknown;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Maps an upstream UNS status to the status the App answers its own caller
|
|
54
|
+
* with. Credential failures are the platform's problem, not the user's
|
|
55
|
+
* session, so a 401 from UNS becomes 502 instead of looking like a logout,
|
|
56
|
+
* and a retryable 403 becomes 503 instead of looking like a denied action.
|
|
57
|
+
*/
|
|
58
|
+
export declare function appStatus(upstream: number, retryable?: boolean): number;
|
|
59
|
+
/** Translates a failed UNS call of the SDK client. */
|
|
60
|
+
export declare function toDataError(error: UnsV2Error): DataError;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime failures of a data call, missing credentials included, are a
|
|
3
|
+
* `DataError`. The SDK's UNS client does the HTTP exchange; its `UnsV2Error`
|
|
4
|
+
* (kept as `cause`) is translated here, and the data layer raises its own codes
|
|
5
|
+
* (BATCH_LIMIT_EXCEEDED, WRITE_ERRORS, ...). `status` is the HTTP status the App
|
|
6
|
+
* should answer its own caller with. Writes that fail validation throw
|
|
7
|
+
* `ZodError`; programming or platform errors, such as invalid client options or
|
|
8
|
+
* a malformed data subject from the gateway, throw `TypeError`.
|
|
9
|
+
*/
|
|
10
|
+
import { UnsV2OutcomeUnknownError } from '../uns-v2/client.js';
|
|
11
|
+
/**
|
|
12
|
+
* Stable `data.reason` codes UNS adds when it refuses App data access; the
|
|
13
|
+
* top-level code stays FORBIDDEN / NOT_FOUND. Only whole-request errors carry
|
|
14
|
+
* them, never per-item results of a batch or transaction.
|
|
15
|
+
*/
|
|
16
|
+
export const ACCESS_REASONS = {
|
|
17
|
+
/** 403: the collection exists, but this App's grant does not cover it or the operation. */
|
|
18
|
+
notGranted: 'COLLECTION_NOT_GRANTED',
|
|
19
|
+
/** 403 or 404: the collection is gone (hard-deleted or archived). */
|
|
20
|
+
notFound: 'COLLECTION_NOT_FOUND',
|
|
21
|
+
/** 403: the grant covers the operation, the App key lacks `data.missingPermission`. */
|
|
22
|
+
permissionMissing: 'APP_PERMISSION_MISSING',
|
|
23
|
+
};
|
|
24
|
+
export class DataError extends Error {
|
|
25
|
+
/** HTTP status the App should answer with (see `appStatus`). */
|
|
26
|
+
status;
|
|
27
|
+
/** UNS error code, e.g. `DUPLICATE_KEY`, or a data-layer code. */
|
|
28
|
+
code;
|
|
29
|
+
/** Stable `data.reason` code, e.g. `COLLECTION_NOT_FOUND` (see ACCESS_REASONS). */
|
|
30
|
+
reason;
|
|
31
|
+
/** HTTP status UNS answered with; 0 when no response arrived. */
|
|
32
|
+
upstreamStatus;
|
|
33
|
+
requestId;
|
|
34
|
+
retryable;
|
|
35
|
+
/** A write may have reached UNS: reconcile before replaying it with a new idempotency key. */
|
|
36
|
+
outcomeUnknown;
|
|
37
|
+
/** The `data` object of the UNS error envelope, or data-layer details. */
|
|
38
|
+
details;
|
|
39
|
+
constructor(init) {
|
|
40
|
+
super(init.message, init.cause === undefined ? undefined : { cause: init.cause });
|
|
41
|
+
this.name = 'DataError';
|
|
42
|
+
this.status = init.status;
|
|
43
|
+
this.code = init.code;
|
|
44
|
+
this.reason = init.reason;
|
|
45
|
+
this.upstreamStatus = init.upstreamStatus ?? 0;
|
|
46
|
+
this.requestId = init.requestId;
|
|
47
|
+
this.retryable = init.retryable ?? false;
|
|
48
|
+
this.outcomeUnknown = init.outcomeUnknown ?? false;
|
|
49
|
+
this.details = init.details ?? {};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Maps an upstream UNS status to the status the App answers its own caller
|
|
54
|
+
* with. Credential failures are the platform's problem, not the user's
|
|
55
|
+
* session, so a 401 from UNS becomes 502 instead of looking like a logout,
|
|
56
|
+
* and a retryable 403 becomes 503 instead of looking like a denied action.
|
|
57
|
+
*/
|
|
58
|
+
export function appStatus(upstream, retryable = false) {
|
|
59
|
+
if (upstream === 401)
|
|
60
|
+
return 502;
|
|
61
|
+
// A retryable refusal is a platform state, not the caller's permission:
|
|
62
|
+
// e.g. FORBIDDEN "hosted App is not ready" right after an import.
|
|
63
|
+
if (upstream === 403 && retryable)
|
|
64
|
+
return 503;
|
|
65
|
+
if (upstream === 400 || upstream === 403 || upstream === 404 || upstream === 409 || upstream === 413 || upstream === 422 || upstream === 429) {
|
|
66
|
+
return upstream;
|
|
67
|
+
}
|
|
68
|
+
if (upstream === 502 || upstream === 503 || upstream === 504)
|
|
69
|
+
return 503;
|
|
70
|
+
if (upstream >= 500)
|
|
71
|
+
return 502;
|
|
72
|
+
return upstream >= 400 ? 400 : 502;
|
|
73
|
+
}
|
|
74
|
+
const CODE_HINTS = {
|
|
75
|
+
UPSERT_REQUIRES_UNIQUE_INDEX: 'An upsert filter must contain `_id` or every field of a unique index that is already ready; a newly declared unique index may still be building.',
|
|
76
|
+
DUPLICATE_KEY: 'A unique index already holds this value. (From restore: an active record took the value meanwhile; nothing was restored.)',
|
|
77
|
+
VERSION_CONFLICT: 'The record changed since it was read; reload it and retry with the new revision.',
|
|
78
|
+
APP_GRANT_REVOKED: "A workspace admin revoked this App's access to the collection; it is not re-granted automatically. Ask the admin to restore the grant.",
|
|
79
|
+
INDEX_QUOTA_EXCEEDED: 'The workspace index quota (200, counting every index that physically exists) is exhausted. Remove unused indexes through the tier0 MCP.',
|
|
80
|
+
COLLECTION_TOO_LARGE: 'archive / restore handle at most 2000 records; stop using a large collection in code instead of archiving it.',
|
|
81
|
+
};
|
|
82
|
+
/** `APP_QUOTA_EXCEEDED` per `data.resource`; each per-App limit is 64. */
|
|
83
|
+
const QUOTA_HINTS = {
|
|
84
|
+
collections: 'This App owns 64 active collections. Archive unused ones through the tier0 MCP.',
|
|
85
|
+
indexes: "This App's collections hold 64 indexes. Drop unused indexes from the declarations, then apply that with schema:replace through the tier0 MCP.",
|
|
86
|
+
archivedCollections: 'This App keeps 64 archived collections. Restore one, or ask a workspace admin to clean up archived collections.',
|
|
87
|
+
};
|
|
88
|
+
/** SDK transport failures: no UNS answer to map, so the data layer names them. */
|
|
89
|
+
const TRANSPORT_FAILURES = {
|
|
90
|
+
UNS_V2_TRANSPORT_TIMEOUT: { code: 'DATA_TIMEOUT', status: 503, retryable: true, message: 'UNS did not answer in time' },
|
|
91
|
+
UNS_V2_TRANSPORT_ERROR: { code: 'DATA_UNREACHABLE', status: 503, retryable: true, message: 'Cannot reach the Tier0 data service' },
|
|
92
|
+
UNS_V2_PROTOCOL_ERROR: { code: 'DATA_BAD_RESPONSE', status: 502, retryable: false, message: 'UNS answered with an invalid response' },
|
|
93
|
+
};
|
|
94
|
+
function codeHint(code, details) {
|
|
95
|
+
if (code === 'APP_QUOTA_EXCEEDED') {
|
|
96
|
+
const resource = typeof details.resource === 'string' ? details.resource : '';
|
|
97
|
+
return QUOTA_HINTS[resource] ?? 'This App reached a collection/index quota. Remove unused collections or indexes through the tier0 MCP.';
|
|
98
|
+
}
|
|
99
|
+
return CODE_HINTS[code];
|
|
100
|
+
}
|
|
101
|
+
function isObject(value) {
|
|
102
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
103
|
+
}
|
|
104
|
+
/** Translates a failed UNS call of the SDK client. */
|
|
105
|
+
export function toDataError(error) {
|
|
106
|
+
const outcomeUnknown = error instanceof UnsV2OutcomeUnknownError;
|
|
107
|
+
// An ingress or load balancer answers 502/503/504 without the UNS envelope during
|
|
108
|
+
// rolling releases and pod restarts: retryable, like any unavailable upstream.
|
|
109
|
+
// UNS v2 routes answer every other error with the envelope (401/403/429 included),
|
|
110
|
+
// so other unenveloped responses stay DATA_BAD_RESPONSE.
|
|
111
|
+
if (error.code === 'UNS_V2_PROTOCOL_ERROR' && (error.status === 502 || error.status === 503 || error.status === 504)) {
|
|
112
|
+
return new DataError({
|
|
113
|
+
message: `The Tier0 data gateway answered ${error.operation} with HTTP ${error.status}; retry shortly${outcomeUnknown ? ' (the write outcome is unknown)' : ''}.`,
|
|
114
|
+
status: 503,
|
|
115
|
+
code: `HTTP_${error.status}`,
|
|
116
|
+
upstreamStatus: error.status,
|
|
117
|
+
retryable: true,
|
|
118
|
+
outcomeUnknown,
|
|
119
|
+
cause: error,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
const transport = TRANSPORT_FAILURES[error.code];
|
|
123
|
+
if (transport) {
|
|
124
|
+
return new DataError({
|
|
125
|
+
message: `${transport.message} (${error.operation})${outcomeUnknown ? '; the write outcome is unknown' : ''}.`,
|
|
126
|
+
status: transport.status,
|
|
127
|
+
code: transport.code,
|
|
128
|
+
upstreamStatus: error.status,
|
|
129
|
+
retryable: transport.retryable,
|
|
130
|
+
outcomeUnknown,
|
|
131
|
+
cause: error,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
const httpStatus = error.status ?? 0;
|
|
135
|
+
const data = isObject(error.data) ? error.data : {};
|
|
136
|
+
// Only `data.reason` is a code; `error.reason` repeats the message text.
|
|
137
|
+
const reason = typeof data.reason === 'string' ? data.reason : undefined;
|
|
138
|
+
const retryable = error.retryable || httpStatus === 503 || httpStatus === 504;
|
|
139
|
+
const code = error.code;
|
|
140
|
+
const msg = error.message;
|
|
141
|
+
const hint = codeHint(code, data);
|
|
142
|
+
let message = `${msg} (${code})`;
|
|
143
|
+
if (httpStatus === 403 && retryable) {
|
|
144
|
+
message = `${msg} (${code}). The platform is still preparing this App; retry shortly.`;
|
|
145
|
+
}
|
|
146
|
+
else if (reason === ACCESS_REASONS.permissionMissing) {
|
|
147
|
+
message =
|
|
148
|
+
data.missingPermission === 'uns.delete'
|
|
149
|
+
? `Deleting records requires the App key to hold uns.delete, and this App's key does not (${code}). ` +
|
|
150
|
+
'Model removal as a status change such as `archived`, or ask a workspace admin to grant uns.delete.'
|
|
151
|
+
: `The App key lacks ${typeof data.missingPermission === 'string' ? data.missingPermission : 'a permission'} for this operation (${code}); ask a workspace admin.`;
|
|
152
|
+
}
|
|
153
|
+
else if (reason === ACCESS_REASONS.notGranted) {
|
|
154
|
+
message = `${message} This App's grant does not cover the collection or operation; ask a workspace admin to restore the grant.`;
|
|
155
|
+
}
|
|
156
|
+
else if (reason === ACCESS_REASONS.notFound) {
|
|
157
|
+
message = `${message} The collection was archived or deleted; the data layer ensures the declared collections again.`;
|
|
158
|
+
}
|
|
159
|
+
else if (httpStatus === 401) {
|
|
160
|
+
message = `Tier0 rejected the App credential for ${error.operation} (${code}). The platform injects TIER0_API_KEY; do not replace it.`;
|
|
161
|
+
}
|
|
162
|
+
else if (hint) {
|
|
163
|
+
message = `${message} ${hint}`;
|
|
164
|
+
}
|
|
165
|
+
return new DataError({
|
|
166
|
+
message,
|
|
167
|
+
status: appStatus(httpStatus, retryable),
|
|
168
|
+
code,
|
|
169
|
+
reason,
|
|
170
|
+
upstreamStatus: httpStatus,
|
|
171
|
+
requestId: error.requestId,
|
|
172
|
+
retryable,
|
|
173
|
+
outcomeUnknown,
|
|
174
|
+
details: data,
|
|
175
|
+
cause: error,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.js","sourceRoot":"","sources":["../../../src/data/error.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Runtime failures of a data call, missing credentials included, are a\n * `DataError`. The SDK's UNS client does the HTTP exchange; its `UnsV2Error`\n * (kept as `cause`) is translated here, and the data layer raises its own codes\n * (BATCH_LIMIT_EXCEEDED, WRITE_ERRORS, ...). `status` is the HTTP status the App\n * should answer its own caller with. Writes that fail validation throw\n * `ZodError`; programming or platform errors, such as invalid client options or\n * a malformed data subject from the gateway, throw `TypeError`.\n */\nimport { UnsV2OutcomeUnknownError, type UnsV2Error } from '../uns-v2/client.js';\n\n/**\n * Stable `data.reason` codes UNS adds when it refuses App data access; the\n * top-level code stays FORBIDDEN / NOT_FOUND. Only whole-request errors carry\n * them, never per-item results of a batch or transaction.\n */\nexport const ACCESS_REASONS = {\n /** 403: the collection exists, but this App's grant does not cover it or the operation. */\n notGranted: 'COLLECTION_NOT_GRANTED',\n /** 403 or 404: the collection is gone (hard-deleted or archived). */\n notFound: 'COLLECTION_NOT_FOUND',\n /** 403: the grant covers the operation, the App key lacks `data.missingPermission`. */\n permissionMissing: 'APP_PERMISSION_MISSING',\n} as const;\n\nexport class DataError extends Error {\n /** HTTP status the App should answer with (see `appStatus`). */\n readonly status: number;\n /** UNS error code, e.g. `DUPLICATE_KEY`, or a data-layer code. */\n readonly code: string;\n /** Stable `data.reason` code, e.g. `COLLECTION_NOT_FOUND` (see ACCESS_REASONS). */\n readonly reason?: string;\n /** HTTP status UNS answered with; 0 when no response arrived. */\n readonly upstreamStatus: number;\n readonly requestId?: string;\n readonly retryable: boolean;\n /** A write may have reached UNS: reconcile before replaying it with a new idempotency key. */\n readonly outcomeUnknown: boolean;\n /** The `data` object of the UNS error envelope, or data-layer details. */\n readonly details: Record<string, unknown>;\n\n constructor(init: {\n message: string;\n status: number;\n code: string;\n reason?: string;\n upstreamStatus?: number;\n requestId?: string;\n retryable?: boolean;\n outcomeUnknown?: boolean;\n details?: Record<string, unknown>;\n cause?: unknown;\n }) {\n super(init.message, init.cause === undefined ? undefined : { cause: init.cause });\n this.name = 'DataError';\n this.status = init.status;\n this.code = init.code;\n this.reason = init.reason;\n this.upstreamStatus = init.upstreamStatus ?? 0;\n this.requestId = init.requestId;\n this.retryable = init.retryable ?? false;\n this.outcomeUnknown = init.outcomeUnknown ?? false;\n this.details = init.details ?? {};\n }\n}\n\n/**\n * Maps an upstream UNS status to the status the App answers its own caller\n * with. Credential failures are the platform's problem, not the user's\n * session, so a 401 from UNS becomes 502 instead of looking like a logout,\n * and a retryable 403 becomes 503 instead of looking like a denied action.\n */\nexport function appStatus(upstream: number, retryable = false): number {\n if (upstream === 401) return 502;\n // A retryable refusal is a platform state, not the caller's permission:\n // e.g. FORBIDDEN \"hosted App is not ready\" right after an import.\n if (upstream === 403 && retryable) return 503;\n if (upstream === 400 || upstream === 403 || upstream === 404 || upstream === 409 || upstream === 413 || upstream === 422 || upstream === 429) {\n return upstream;\n }\n if (upstream === 502 || upstream === 503 || upstream === 504) return 503;\n if (upstream >= 500) return 502;\n return upstream >= 400 ? 400 : 502;\n}\n\nconst CODE_HINTS: Record<string, string> = {\n UPSERT_REQUIRES_UNIQUE_INDEX:\n 'An upsert filter must contain `_id` or every field of a unique index that is already ready; a newly declared unique index may still be building.',\n DUPLICATE_KEY:\n 'A unique index already holds this value. (From restore: an active record took the value meanwhile; nothing was restored.)',\n VERSION_CONFLICT: 'The record changed since it was read; reload it and retry with the new revision.',\n APP_GRANT_REVOKED:\n \"A workspace admin revoked this App's access to the collection; it is not re-granted automatically. Ask the admin to restore the grant.\",\n INDEX_QUOTA_EXCEEDED:\n 'The workspace index quota (200, counting every index that physically exists) is exhausted. Remove unused indexes through the tier0 MCP.',\n COLLECTION_TOO_LARGE:\n 'archive / restore handle at most 2000 records; stop using a large collection in code instead of archiving it.',\n};\n\n/** `APP_QUOTA_EXCEEDED` per `data.resource`; each per-App limit is 64. */\nconst QUOTA_HINTS: Record<string, string> = {\n collections: 'This App owns 64 active collections. Archive unused ones through the tier0 MCP.',\n indexes: \"This App's collections hold 64 indexes. Drop unused indexes from the declarations, then apply that with schema:replace through the tier0 MCP.\",\n archivedCollections:\n 'This App keeps 64 archived collections. Restore one, or ask a workspace admin to clean up archived collections.',\n};\n\n/** SDK transport failures: no UNS answer to map, so the data layer names them. */\nconst TRANSPORT_FAILURES: Record<string, { code: string; status: number; retryable: boolean; message: string }> = {\n UNS_V2_TRANSPORT_TIMEOUT: { code: 'DATA_TIMEOUT', status: 503, retryable: true, message: 'UNS did not answer in time' },\n UNS_V2_TRANSPORT_ERROR: { code: 'DATA_UNREACHABLE', status: 503, retryable: true, message: 'Cannot reach the Tier0 data service' },\n UNS_V2_PROTOCOL_ERROR: { code: 'DATA_BAD_RESPONSE', status: 502, retryable: false, message: 'UNS answered with an invalid response' },\n};\n\nfunction codeHint(code: string, details: Record<string, unknown>): string | undefined {\n if (code === 'APP_QUOTA_EXCEEDED') {\n const resource = typeof details.resource === 'string' ? details.resource : '';\n return QUOTA_HINTS[resource] ?? 'This App reached a collection/index quota. Remove unused collections or indexes through the tier0 MCP.';\n }\n return CODE_HINTS[code];\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** Translates a failed UNS call of the SDK client. */\nexport function toDataError(error: UnsV2Error): DataError {\n const outcomeUnknown = error instanceof UnsV2OutcomeUnknownError;\n // An ingress or load balancer answers 502/503/504 without the UNS envelope during\n // rolling releases and pod restarts: retryable, like any unavailable upstream.\n // UNS v2 routes answer every other error with the envelope (401/403/429 included),\n // so other unenveloped responses stay DATA_BAD_RESPONSE.\n if (error.code === 'UNS_V2_PROTOCOL_ERROR' && (error.status === 502 || error.status === 503 || error.status === 504)) {\n return new DataError({\n message: `The Tier0 data gateway answered ${error.operation} with HTTP ${error.status}; retry shortly${outcomeUnknown ? ' (the write outcome is unknown)' : ''}.`,\n status: 503,\n code: `HTTP_${error.status}`,\n upstreamStatus: error.status,\n retryable: true,\n outcomeUnknown,\n cause: error,\n });\n }\n const transport = TRANSPORT_FAILURES[error.code];\n if (transport) {\n return new DataError({\n message: `${transport.message} (${error.operation})${outcomeUnknown ? '; the write outcome is unknown' : ''}.`,\n status: transport.status,\n code: transport.code,\n upstreamStatus: error.status,\n retryable: transport.retryable,\n outcomeUnknown,\n cause: error,\n });\n }\n\n const httpStatus = error.status ?? 0;\n const data = isObject(error.data) ? error.data : {};\n // Only `data.reason` is a code; `error.reason` repeats the message text.\n const reason = typeof data.reason === 'string' ? data.reason : undefined;\n const retryable = error.retryable || httpStatus === 503 || httpStatus === 504;\n const code = error.code;\n const msg = error.message;\n const hint = codeHint(code, data);\n let message = `${msg} (${code})`;\n if (httpStatus === 403 && retryable) {\n message = `${msg} (${code}). The platform is still preparing this App; retry shortly.`;\n } else if (reason === ACCESS_REASONS.permissionMissing) {\n message =\n data.missingPermission === 'uns.delete'\n ? `Deleting records requires the App key to hold uns.delete, and this App's key does not (${code}). ` +\n 'Model removal as a status change such as `archived`, or ask a workspace admin to grant uns.delete.'\n : `The App key lacks ${typeof data.missingPermission === 'string' ? data.missingPermission : 'a permission'} for this operation (${code}); ask a workspace admin.`;\n } else if (reason === ACCESS_REASONS.notGranted) {\n message = `${message} This App's grant does not cover the collection or operation; ask a workspace admin to restore the grant.`;\n } else if (reason === ACCESS_REASONS.notFound) {\n message = `${message} The collection was archived or deleted; the data layer ensures the declared collections again.`;\n } else if (httpStatus === 401) {\n message = `Tier0 rejected the App credential for ${error.operation} (${code}). The platform injects TIER0_API_KEY; do not replace it.`;\n } else if (hint) {\n message = `${message} ${hint}`;\n }\n\n return new DataError({\n message,\n status: appStatus(httpStatus, retryable),\n code,\n reason,\n upstreamStatus: httpStatus,\n requestId: error.requestId,\n retryable,\n outcomeUnknown,\n details: data,\n cause: error,\n });\n}\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@tier0/sdk-v2/data` — server-only App data layer over Tier0 UNS collections.
|
|
3
|
+
*
|
|
4
|
+
* import { createDataClient, defineCollection } from '@tier0/sdk-v2/data';
|
|
5
|
+
*
|
|
6
|
+
* const data = createDataClient({ collections: [workOrders] });
|
|
7
|
+
* const open = await data.collection(workOrders).find({ status: 'OPEN' }, { limit: 50 }).toArray();
|
|
8
|
+
*
|
|
9
|
+
* Declarations are ensured in one batch on first access. Requires `zod` 4.
|
|
10
|
+
* Client code imports declarations and types from `@tier0/sdk-v2/data/define`.
|
|
11
|
+
*/
|
|
12
|
+
export { createDataClient } from './client.js';
|
|
13
|
+
export type { DataClient, DataClientConfig, TransactAction, TransactResult, TransactResultItem, TransactStep } from './client.js';
|
|
14
|
+
export type { DataEnvironment, EnsureConflict, EnsureNote, EnsureResult, EnsureState, EnsureWarning, Logger } from './bootstrap.js';
|
|
15
|
+
export { MAX_ATOMIC_ITEMS } from './collection.js';
|
|
16
|
+
export type { BulkOperation, Collection, Cursor, FindOneAndOptions, FindOptions, FindPageOptions, Projection, Update, UpdateOptions, WithMeta } from './collection.js';
|
|
17
|
+
export { currentDataSubject, runAsApp, runWithRequestContext } from './context.js';
|
|
18
|
+
export { ACCESS_REASONS, DataError } from './error.js';
|
|
19
|
+
export * from './declarations.js';
|
|
20
|
+
export { toSortPairs } from './sort.js';
|
|
21
|
+
export type { Filter, Sort, SortDirection, SortPairs } from './sort.js';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@tier0/sdk-v2/data` — server-only App data layer over Tier0 UNS collections.
|
|
3
|
+
*
|
|
4
|
+
* import { createDataClient, defineCollection } from '@tier0/sdk-v2/data';
|
|
5
|
+
*
|
|
6
|
+
* const data = createDataClient({ collections: [workOrders] });
|
|
7
|
+
* const open = await data.collection(workOrders).find({ status: 'OPEN' }, { limit: 50 }).toArray();
|
|
8
|
+
*
|
|
9
|
+
* Declarations are ensured in one batch on first access. Requires `zod` 4.
|
|
10
|
+
* Client code imports declarations and types from `@tier0/sdk-v2/data/define`.
|
|
11
|
+
*/
|
|
12
|
+
export { createDataClient } from './client.js';
|
|
13
|
+
export { MAX_ATOMIC_ITEMS } from './collection.js';
|
|
14
|
+
export { currentDataSubject, runAsApp, runWithRequestContext } from './context.js';
|
|
15
|
+
export { ACCESS_REASONS, DataError } from './error.js';
|
|
16
|
+
export * from './declarations.js';
|
|
17
|
+
export { toSortPairs } from './sort.js';
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/data/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvD,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC","sourcesContent":["/**\n * `@tier0/sdk-v2/data` — server-only App data layer over Tier0 UNS collections.\n *\n * import { createDataClient, defineCollection } from '@tier0/sdk-v2/data';\n *\n * const data = createDataClient({ collections: [workOrders] });\n * const open = await data.collection(workOrders).find({ status: 'OPEN' }, { limit: 50 }).toArray();\n *\n * Declarations are ensured in one batch on first access. Requires `zod` 4.\n * Client code imports declarations and types from `@tier0/sdk-v2/data/define`.\n */\nexport { createDataClient } from './client.js';\nexport type { DataClient, DataClientConfig, TransactAction, TransactResult, TransactResultItem, TransactStep } from './client.js';\nexport type { DataEnvironment, EnsureConflict, EnsureNote, EnsureResult, EnsureState, EnsureWarning, Logger } from './bootstrap.js';\nexport { MAX_ATOMIC_ITEMS } from './collection.js';\nexport type { BulkOperation, Collection, Cursor, FindOneAndOptions, FindOptions, FindPageOptions, Projection, Update, UpdateOptions, WithMeta } from './collection.js';\nexport { currentDataSubject, runAsApp, runWithRequestContext } from './context.js';\nexport { ACCESS_REASONS, DataError } from './error.js';\nexport * from './declarations.js';\nexport { toSortPairs } from './sort.js';\nexport type { Filter, Sort, SortDirection, SortPairs } from './sort.js';\n"]}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod 4 → UNS record schema normalizer, plus write-time validation.
|
|
3
|
+
*
|
|
4
|
+
* UNS stores one closed JSON-schema subset per collection: `type`,
|
|
5
|
+
* `properties`, `required`, `additionalProperties: false`, `items`, `enum`,
|
|
6
|
+
* `minimum`, `maximum`, `title`, `description`. `toRecordSchema` converts the
|
|
7
|
+
* `z.toJSONSchema` output into exactly that subset and rejects every other
|
|
8
|
+
* keyword with a concrete replacement, so a declaration that cannot be stored
|
|
9
|
+
* fails when it is compiled (an App can compile its declarations at build
|
|
10
|
+
* time) instead of on the first request.
|
|
11
|
+
*/
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import { type CollectionDefinition } from './define.js';
|
|
14
|
+
export type RecordSchemaType = 'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean';
|
|
15
|
+
export type EnumValue = string | number | boolean;
|
|
16
|
+
export interface RecordSchema {
|
|
17
|
+
type: RecordSchemaType;
|
|
18
|
+
title?: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
properties?: Record<string, RecordSchema>;
|
|
21
|
+
required?: string[];
|
|
22
|
+
additionalProperties?: false;
|
|
23
|
+
items?: RecordSchema;
|
|
24
|
+
enum?: EnumValue[];
|
|
25
|
+
minimum?: number;
|
|
26
|
+
maximum?: number;
|
|
27
|
+
}
|
|
28
|
+
export interface NormalizedIndex {
|
|
29
|
+
path?: string;
|
|
30
|
+
paths?: string[];
|
|
31
|
+
unique?: true;
|
|
32
|
+
kind?: 'gin';
|
|
33
|
+
}
|
|
34
|
+
/** One ensure item, exactly as it is sent to `/uns/app/collections/ensure`. */
|
|
35
|
+
export interface CompiledCollection {
|
|
36
|
+
alias: string;
|
|
37
|
+
recordSchema: RecordSchema;
|
|
38
|
+
indexes: NormalizedIndex[];
|
|
39
|
+
description?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface SchemaIssue {
|
|
42
|
+
path: string;
|
|
43
|
+
message: string;
|
|
44
|
+
}
|
|
45
|
+
export declare class CollectionSchemaError extends Error {
|
|
46
|
+
readonly alias: string;
|
|
47
|
+
readonly issues: SchemaIssue[];
|
|
48
|
+
constructor(alias: string, issues: SchemaIssue[]);
|
|
49
|
+
}
|
|
50
|
+
/** UNS limits (unsmeta Schema.validate and collection indexes); title/description are UTF-8 bytes. */
|
|
51
|
+
export declare const SCHEMA_LIMITS: {
|
|
52
|
+
readonly depth: 8;
|
|
53
|
+
readonly properties: 128;
|
|
54
|
+
readonly enumValues: 100;
|
|
55
|
+
readonly title: 512;
|
|
56
|
+
readonly description: 2048;
|
|
57
|
+
readonly indexes: 16;
|
|
58
|
+
readonly indexPaths: 3;
|
|
59
|
+
};
|
|
60
|
+
type JsonNode = Record<string, unknown>;
|
|
61
|
+
/** Raw `z.toJSONSchema` output; exported for the snapshot tests. */
|
|
62
|
+
export declare function zodJsonSchema(schema: z.ZodType): JsonNode;
|
|
63
|
+
/** Converts a Zod object schema to the UNS record-schema subset or throws `CollectionSchemaError`. */
|
|
64
|
+
export declare function toRecordSchema(alias: string, schema: z.ZodType): RecordSchema;
|
|
65
|
+
/** Resolves a dotted business path in a record schema; array levels accept index segments. */
|
|
66
|
+
export declare function recordSchemaAt(schema: RecordSchema, path: string): RecordSchema | undefined;
|
|
67
|
+
/** Ensure payload for one declaration; memoized per definition object. */
|
|
68
|
+
export declare function compileCollection(definition: CollectionDefinition): CompiledCollection;
|
|
69
|
+
/** Splits `_id` / `_meta` off a document and strictly validates the body. */
|
|
70
|
+
export declare function validateDocument(definition: CollectionDefinition, document: Record<string, unknown>): {
|
|
71
|
+
id?: string;
|
|
72
|
+
data: Record<string, unknown>;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Validates `data` of a transaction step. Fields filled by `bindings`
|
|
76
|
+
* (`data.<field>...`) are checked only for being declared; every literal
|
|
77
|
+
* field is strictly validated, and other required fields must be present.
|
|
78
|
+
*/
|
|
79
|
+
export declare function validateStepData(definition: CollectionDefinition, data: Record<string, unknown>, boundFields: readonly string[]): Record<string, unknown>;
|
|
80
|
+
/** Validates update-operator documents against the declaration (paths and values). */
|
|
81
|
+
export declare function validateUpdate(definition: CollectionDefinition, update: Record<string, unknown>): Record<string, unknown>;
|
|
82
|
+
export {};
|