@sequenceholdings/artifact-studio 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -1
- package/VERSION-PIN.md +9 -0
- package/dist/active-deploy-policy.d.ts +9 -3
- package/dist/active-deploy-policy.js +20 -8
- package/dist/artifact-env-bindings.d.ts +9 -0
- package/dist/artifact-env-bindings.js +32 -0
- package/dist/build.js +6 -0
- package/dist/cli.js +61 -12
- package/dist/deployment-validation.d.ts +2 -0
- package/dist/deployment-validation.js +2 -0
- package/dist/dev-link.js +28 -2
- package/dist/env-binding-scan.d.ts +10 -0
- package/dist/env-binding-scan.js +179 -0
- package/dist/env-bindings.d.ts +52 -0
- package/dist/env-bindings.js +180 -0
- package/dist/gateway/control.d.ts +33 -0
- package/dist/gateway/control.js +29 -0
- package/dist/gateway/hosted-proxy.d.ts +5 -0
- package/dist/gateway/hosted-proxy.js +4 -1
- package/dist/gateway/lattice-invoke.d.ts +48 -0
- package/dist/gateway/lattice-invoke.js +245 -0
- package/dist/gateway/lattice-upstream.d.ts +38 -0
- package/dist/gateway/lattice-upstream.js +136 -0
- package/dist/gateway/server.js +2 -3
- package/dist/gateway/session.d.ts +3 -1
- package/dist/gateway/session.js +10 -3
- package/dist/manifest-next.d.ts +55 -0
- package/dist/manifest-next.js +35 -2
- package/dist/manifest-static.d.ts +35 -0
- package/dist/manifest-static.js +12 -0
- package/dist/manifest.d.ts +48 -0
- package/dist/next-build.d.ts +2 -1
- package/dist/next-build.js +12 -7
- package/dist/offline/cache.d.ts +4 -0
- package/dist/offline/cache.js +7 -0
- package/dist/offline/connector.d.ts +26 -0
- package/dist/offline/connector.js +118 -0
- package/dist/offline/crypto.d.ts +5 -0
- package/dist/offline/crypto.js +24 -0
- package/dist/offline/index.d.ts +8 -0
- package/dist/offline/index.js +7 -0
- package/dist/offline/indexed-db.d.ts +10 -0
- package/dist/offline/indexed-db.js +104 -0
- package/dist/offline/outbox.d.ts +7 -0
- package/dist/offline/outbox.js +46 -0
- package/dist/offline/replay.d.ts +25 -0
- package/dist/offline/replay.js +192 -0
- package/dist/offline/secure-store.d.ts +6 -0
- package/dist/offline/secure-store.js +51 -0
- package/dist/offline/types.d.ts +162 -0
- package/dist/offline/types.js +1 -0
- package/dist/orm-json-scalars.d.ts +21 -0
- package/dist/orm-json-scalars.js +21 -0
- package/dist/runtime-contracts.d.ts +7 -7
- package/dist/sdk-orm.d.ts +7 -1
- package/dist/sdk-orm.js +12 -5
- package/dist/sdk.d.ts +126 -0
- package/dist/server/broker-contract.d.ts +191 -5
- package/dist/server/broker-contract.js +142 -1
- package/dist/server/client.d.ts +60 -12
- package/dist/server/client.js +143 -20
- package/dist/server/errors.d.ts +26 -0
- package/dist/server/errors.js +29 -0
- package/dist/server/managed-server-path.d.ts +6 -0
- package/dist/server/managed-server-path.js +14 -0
- package/dist/server/processes.d.ts +290 -0
- package/dist/server/processes.js +56 -0
- package/dist/server/request-context.d.ts +6 -0
- package/dist/server/request-context.js +10 -1
- package/dist/server.d.ts +5 -1
- package/dist/server.js +1 -0
- package/dist/source-resolver.d.ts +9 -2
- package/dist/source-resolver.js +55 -8
- package/dist/templates/nextjs/AGENTS.md +10 -0
- package/dist/templates/nextjs/CLAUDE.md +1 -0
- package/dist/templates/nextjs/README.md +88 -0
- package/dist/templates/react-vite/AGENTS.md +8 -88
- package/dist/templates/react-vite/CLAUDE.md +0 -6
- package/dist/templates/react-vite/package.json +1 -1
- package/dist/templates/react-vite/src/App.tsx +37 -14
- package/dist/templates/react-vite/src/styles.css +10 -0
- package/package.json +7 -3
- package/templates/nextjs/AGENTS.md +10 -0
- package/templates/nextjs/CLAUDE.md +1 -0
- package/templates/nextjs/README.md +88 -0
- package/templates/react-vite/AGENTS.md +8 -88
- package/templates/react-vite/CLAUDE.md +0 -6
- package/templates/react-vite/package.json +1 -1
- package/templates/react-vite/src/App.tsx +37 -14
- package/templates/react-vite/src/styles.css +10 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
function isEncryptedRecord(value) {
|
|
2
|
+
if (!value || typeof value !== 'object')
|
|
3
|
+
return false;
|
|
4
|
+
return ('iv' in value &&
|
|
5
|
+
'ciphertext' in value &&
|
|
6
|
+
Array.isArray(value.iv) &&
|
|
7
|
+
Array.isArray(value.ciphertext));
|
|
8
|
+
}
|
|
9
|
+
export function createEncryptedOfflineStore({ kv, crypto, namespace, }) {
|
|
10
|
+
if (namespace.length === 0 || namespace.includes('\n')) {
|
|
11
|
+
throw new Error('Offline storage namespace is required');
|
|
12
|
+
}
|
|
13
|
+
const prefix = `${namespace}:`;
|
|
14
|
+
const scopedKey = (key) => `${prefix}${key}`;
|
|
15
|
+
async function scopedKeys(store) {
|
|
16
|
+
return (await kv.keys({ store }))
|
|
17
|
+
.filter((key) => key.startsWith(prefix))
|
|
18
|
+
.map((key) => key.slice(prefix.length));
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
async get({ store, key, }) {
|
|
22
|
+
const scoped = scopedKey(key);
|
|
23
|
+
const record = await kv.get({ store, key: scoped });
|
|
24
|
+
if (!isEncryptedRecord(record))
|
|
25
|
+
return undefined;
|
|
26
|
+
try {
|
|
27
|
+
// The caller owns each logical key's schema; the encrypted store is
|
|
28
|
+
// intentionally heterogeneous and cannot infer T after JSON decode.
|
|
29
|
+
return (await crypto.decrypt({ record }));
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
await kv.delete({ store, key: scoped });
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
async set({ store, key, value }) {
|
|
37
|
+
await kv.set({
|
|
38
|
+
store,
|
|
39
|
+
key: scopedKey(key),
|
|
40
|
+
value: await crypto.encrypt({ value }),
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
async delete({ store, key }) {
|
|
44
|
+
await kv.delete({ store, key: scopedKey(key) });
|
|
45
|
+
},
|
|
46
|
+
keys: ({ store }) => scopedKeys(store),
|
|
47
|
+
async clear({ store }) {
|
|
48
|
+
await Promise.all((await scopedKeys(store)).map((key) => kv.delete({ store, key: scopedKey(key) })));
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import type { SequenceApiFetchResponse, SequenceOfflineNetwork, SequenceOfflineRequest } from '../sdk.js';
|
|
2
|
+
export type OfflineStoreName = 'cache' | 'outbox' | 'accesslog';
|
|
3
|
+
export interface OfflineKvStore {
|
|
4
|
+
get(input: {
|
|
5
|
+
store: OfflineStoreName;
|
|
6
|
+
key: string;
|
|
7
|
+
}): Promise<unknown>;
|
|
8
|
+
set(input: {
|
|
9
|
+
store: OfflineStoreName;
|
|
10
|
+
key: string;
|
|
11
|
+
value: unknown;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
delete(input: {
|
|
14
|
+
store: OfflineStoreName;
|
|
15
|
+
key: string;
|
|
16
|
+
}): Promise<void>;
|
|
17
|
+
keys(input: {
|
|
18
|
+
store: OfflineStoreName;
|
|
19
|
+
}): Promise<string[]>;
|
|
20
|
+
}
|
|
21
|
+
export interface OfflineEncryptedRecord {
|
|
22
|
+
iv: number[];
|
|
23
|
+
ciphertext: number[];
|
|
24
|
+
}
|
|
25
|
+
export interface OfflineCrypto {
|
|
26
|
+
encrypt(input: {
|
|
27
|
+
value: unknown;
|
|
28
|
+
}): Promise<OfflineEncryptedRecord>;
|
|
29
|
+
decrypt(input: {
|
|
30
|
+
record: OfflineEncryptedRecord;
|
|
31
|
+
}): Promise<unknown>;
|
|
32
|
+
}
|
|
33
|
+
export interface EncryptedOfflineStore {
|
|
34
|
+
get<T = unknown>(input: {
|
|
35
|
+
store: OfflineStoreName;
|
|
36
|
+
key: string;
|
|
37
|
+
}): Promise<T | undefined>;
|
|
38
|
+
set(input: {
|
|
39
|
+
store: OfflineStoreName;
|
|
40
|
+
key: string;
|
|
41
|
+
value: unknown;
|
|
42
|
+
}): Promise<void>;
|
|
43
|
+
delete(input: {
|
|
44
|
+
store: OfflineStoreName;
|
|
45
|
+
key: string;
|
|
46
|
+
}): Promise<void>;
|
|
47
|
+
keys(input: {
|
|
48
|
+
store: OfflineStoreName;
|
|
49
|
+
}): Promise<string[]>;
|
|
50
|
+
clear(input: {
|
|
51
|
+
store: OfflineStoreName;
|
|
52
|
+
}): Promise<void>;
|
|
53
|
+
}
|
|
54
|
+
export type OfflineFailureKind = 'transient' | 'invalid' | 'auth' | 'conflict';
|
|
55
|
+
export type OfflineOutboxStatus = 'pending' | 'inflight' | 'failed' | 'conflict';
|
|
56
|
+
export interface OfflineConflictField {
|
|
57
|
+
key: string;
|
|
58
|
+
mine: unknown;
|
|
59
|
+
theirs: unknown;
|
|
60
|
+
}
|
|
61
|
+
export interface OfflineConflictInfo {
|
|
62
|
+
fields: OfflineConflictField[];
|
|
63
|
+
observedAt?: string;
|
|
64
|
+
serverUpdatedAt?: string;
|
|
65
|
+
}
|
|
66
|
+
export interface OfflineOutboxEntry {
|
|
67
|
+
id: string;
|
|
68
|
+
sequence: number;
|
|
69
|
+
request: SequenceOfflineRequest;
|
|
70
|
+
entity: string;
|
|
71
|
+
capturedAt: string;
|
|
72
|
+
attempts: number;
|
|
73
|
+
status: OfflineOutboxStatus;
|
|
74
|
+
observed?: Record<string, unknown>;
|
|
75
|
+
optimisticId?: string;
|
|
76
|
+
failureKind?: OfflineFailureKind;
|
|
77
|
+
lastError?: string;
|
|
78
|
+
conflict?: OfflineConflictInfo;
|
|
79
|
+
force?: boolean;
|
|
80
|
+
}
|
|
81
|
+
export interface OfflineOutbox {
|
|
82
|
+
enqueue(input: {
|
|
83
|
+
id?: string;
|
|
84
|
+
request: SequenceOfflineRequest;
|
|
85
|
+
entity: string;
|
|
86
|
+
observed?: Record<string, unknown>;
|
|
87
|
+
optimisticId?: string;
|
|
88
|
+
}): Promise<OfflineOutboxEntry>;
|
|
89
|
+
list(): Promise<OfflineOutboxEntry[]>;
|
|
90
|
+
update(input: {
|
|
91
|
+
id: string;
|
|
92
|
+
patch: Partial<OfflineOutboxEntry>;
|
|
93
|
+
}): Promise<void>;
|
|
94
|
+
remove(input: {
|
|
95
|
+
id: string;
|
|
96
|
+
}): Promise<void>;
|
|
97
|
+
}
|
|
98
|
+
export interface OfflineReadDescriptor {
|
|
99
|
+
key: string;
|
|
100
|
+
ttlMs: number;
|
|
101
|
+
entity: string;
|
|
102
|
+
}
|
|
103
|
+
export interface OfflineReadPolicy {
|
|
104
|
+
match(request: SequenceOfflineRequest): OfflineReadDescriptor | null;
|
|
105
|
+
}
|
|
106
|
+
export interface OfflineCacheEntry {
|
|
107
|
+
response: SequenceApiFetchResponse;
|
|
108
|
+
cachedAt: number;
|
|
109
|
+
expiresAt: number;
|
|
110
|
+
entity: string;
|
|
111
|
+
}
|
|
112
|
+
export interface OfflineCache {
|
|
113
|
+
read(input: {
|
|
114
|
+
key: string;
|
|
115
|
+
}): Promise<OfflineCacheEntry | undefined>;
|
|
116
|
+
write(input: {
|
|
117
|
+
key: string;
|
|
118
|
+
entry: OfflineCacheEntry;
|
|
119
|
+
}): Promise<void>;
|
|
120
|
+
remove(input: {
|
|
121
|
+
key: string;
|
|
122
|
+
}): Promise<void>;
|
|
123
|
+
}
|
|
124
|
+
export interface OfflineMutationDescriptor {
|
|
125
|
+
entity: string;
|
|
126
|
+
label(entry: OfflineOutboxEntry): string;
|
|
127
|
+
capture?(input: {
|
|
128
|
+
request: SequenceOfflineRequest;
|
|
129
|
+
}): Promise<Record<string, unknown> | undefined>;
|
|
130
|
+
optimisticApply?(input: {
|
|
131
|
+
entry: OfflineOutboxEntry;
|
|
132
|
+
}): Promise<void> | void;
|
|
133
|
+
optimisticResponse?(input: {
|
|
134
|
+
entry: OfflineOutboxEntry;
|
|
135
|
+
}): SequenceApiFetchResponse;
|
|
136
|
+
fetchCurrent?(input: {
|
|
137
|
+
entry: OfflineOutboxEntry;
|
|
138
|
+
network: SequenceOfflineNetwork;
|
|
139
|
+
}): Promise<unknown>;
|
|
140
|
+
detectConflict?(input: {
|
|
141
|
+
entry: OfflineOutboxEntry;
|
|
142
|
+
current: unknown;
|
|
143
|
+
}): OfflineConflictInfo | null;
|
|
144
|
+
reconcile?(input: {
|
|
145
|
+
entry: OfflineOutboxEntry;
|
|
146
|
+
response: SequenceApiFetchResponse;
|
|
147
|
+
}): Promise<void> | void;
|
|
148
|
+
rollback?(input: {
|
|
149
|
+
entry: OfflineOutboxEntry;
|
|
150
|
+
}): Promise<void> | void;
|
|
151
|
+
}
|
|
152
|
+
export interface OfflineMutationPolicy {
|
|
153
|
+
match(request: SequenceOfflineRequest): OfflineMutationDescriptor | null;
|
|
154
|
+
}
|
|
155
|
+
export interface OfflineUnresolvedWrite {
|
|
156
|
+
id: string;
|
|
157
|
+
label: string;
|
|
158
|
+
capturedAt: string;
|
|
159
|
+
kind: OfflineFailureKind;
|
|
160
|
+
error?: string;
|
|
161
|
+
conflict?: OfflineConflictInfo;
|
|
162
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ORM data plane's opt-in exact-number wire form (orm-data-plane/src/protocol.ts).
|
|
3
|
+
* By default numeric and bigint values come back as JSON numbers, which JavaScript
|
|
4
|
+
* rounds past 15-17 significant digits. With `lossless-v1` they come back as strings
|
|
5
|
+
* ("250000.00", "9007199254740993"), and a successful response acknowledges the form
|
|
6
|
+
* with the same header. Variables may carry numeric and bigint values as decimal
|
|
7
|
+
* strings in either form.
|
|
8
|
+
*/
|
|
9
|
+
export declare const ORM_JSON_SCALARS_HEADER = "x-sequence-orm-json-scalars";
|
|
10
|
+
export declare const ORM_LOSSLESS_JSON_SCALARS = "lossless-v1";
|
|
11
|
+
export type ArtifactOrmJsonScalars = typeof ORM_LOSSLESS_JSON_SCALARS;
|
|
12
|
+
/**
|
|
13
|
+
* An executor that asked for exact numbers refuses a successful result the platform
|
|
14
|
+
* did not acknowledge, because its numbers may already be rounded. Failed responses
|
|
15
|
+
* never acknowledge and keep their own error.
|
|
16
|
+
*/
|
|
17
|
+
export declare function assertJsonScalarsAcknowledged({ requested, acknowledged, status }: {
|
|
18
|
+
requested: ArtifactOrmJsonScalars | undefined;
|
|
19
|
+
acknowledged: string | null | undefined;
|
|
20
|
+
status: number;
|
|
21
|
+
}): void;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { OrmOperationError } from '@sequenceholdings/orm/client';
|
|
2
|
+
/**
|
|
3
|
+
* The ORM data plane's opt-in exact-number wire form (orm-data-plane/src/protocol.ts).
|
|
4
|
+
* By default numeric and bigint values come back as JSON numbers, which JavaScript
|
|
5
|
+
* rounds past 15-17 significant digits. With `lossless-v1` they come back as strings
|
|
6
|
+
* ("250000.00", "9007199254740993"), and a successful response acknowledges the form
|
|
7
|
+
* with the same header. Variables may carry numeric and bigint values as decimal
|
|
8
|
+
* strings in either form.
|
|
9
|
+
*/
|
|
10
|
+
export const ORM_JSON_SCALARS_HEADER = 'x-sequence-orm-json-scalars';
|
|
11
|
+
export const ORM_LOSSLESS_JSON_SCALARS = 'lossless-v1';
|
|
12
|
+
/**
|
|
13
|
+
* An executor that asked for exact numbers refuses a successful result the platform
|
|
14
|
+
* did not acknowledge, because its numbers may already be rounded. Failed responses
|
|
15
|
+
* never acknowledge and keep their own error.
|
|
16
|
+
*/
|
|
17
|
+
export function assertJsonScalarsAcknowledged({ requested, acknowledged, status }) {
|
|
18
|
+
if (requested === undefined || acknowledged === requested)
|
|
19
|
+
return;
|
|
20
|
+
throw new OrmOperationError(`Atlas did not confirm ${requested} numbers for this ORM response, so its numeric and bigint values may be rounded; update Atlas before relying on exact numbers`, status, 'LOSSLESS_TRANSPORT_UNAVAILABLE');
|
|
21
|
+
}
|
|
@@ -72,9 +72,9 @@ export declare const artifactOperationSchema: z.ZodDiscriminatedUnion<[z.ZodObje
|
|
|
72
72
|
projectId: z.ZodString;
|
|
73
73
|
environment: z.ZodString;
|
|
74
74
|
kind: z.ZodEnum<{
|
|
75
|
-
preview: "preview";
|
|
76
75
|
build: "build";
|
|
77
76
|
deploy: "deploy";
|
|
77
|
+
preview: "preview";
|
|
78
78
|
rollback: "rollback";
|
|
79
79
|
suspend: "suspend";
|
|
80
80
|
delete: "delete";
|
|
@@ -92,9 +92,9 @@ export declare const artifactOperationSchema: z.ZodDiscriminatedUnion<[z.ZodObje
|
|
|
92
92
|
projectId: z.ZodString;
|
|
93
93
|
environment: z.ZodString;
|
|
94
94
|
kind: z.ZodEnum<{
|
|
95
|
-
preview: "preview";
|
|
96
95
|
build: "build";
|
|
97
96
|
deploy: "deploy";
|
|
97
|
+
preview: "preview";
|
|
98
98
|
rollback: "rollback";
|
|
99
99
|
suspend: "suspend";
|
|
100
100
|
delete: "delete";
|
|
@@ -109,9 +109,9 @@ export declare const artifactOperationSchema: z.ZodDiscriminatedUnion<[z.ZodObje
|
|
|
109
109
|
projectId: z.ZodString;
|
|
110
110
|
environment: z.ZodString;
|
|
111
111
|
kind: z.ZodEnum<{
|
|
112
|
-
preview: "preview";
|
|
113
112
|
build: "build";
|
|
114
113
|
deploy: "deploy";
|
|
114
|
+
preview: "preview";
|
|
115
115
|
rollback: "rollback";
|
|
116
116
|
suspend: "suspend";
|
|
117
117
|
delete: "delete";
|
|
@@ -130,9 +130,9 @@ export declare const artifactOperationSchema: z.ZodDiscriminatedUnion<[z.ZodObje
|
|
|
130
130
|
projectId: z.ZodString;
|
|
131
131
|
environment: z.ZodString;
|
|
132
132
|
kind: z.ZodEnum<{
|
|
133
|
-
preview: "preview";
|
|
134
133
|
build: "build";
|
|
135
134
|
deploy: "deploy";
|
|
135
|
+
preview: "preview";
|
|
136
136
|
rollback: "rollback";
|
|
137
137
|
suspend: "suspend";
|
|
138
138
|
delete: "delete";
|
|
@@ -147,9 +147,9 @@ export declare const artifactOperationSchema: z.ZodDiscriminatedUnion<[z.ZodObje
|
|
|
147
147
|
projectId: z.ZodString;
|
|
148
148
|
environment: z.ZodString;
|
|
149
149
|
kind: z.ZodEnum<{
|
|
150
|
-
preview: "preview";
|
|
151
150
|
build: "build";
|
|
152
151
|
deploy: "deploy";
|
|
152
|
+
preview: "preview";
|
|
153
153
|
rollback: "rollback";
|
|
154
154
|
suspend: "suspend";
|
|
155
155
|
delete: "delete";
|
|
@@ -164,9 +164,9 @@ export declare const artifactRuntimeSessionSchema: z.ZodObject<{
|
|
|
164
164
|
projectId: z.ZodString;
|
|
165
165
|
environment: z.ZodString;
|
|
166
166
|
mode: z.ZodEnum<{
|
|
167
|
+
local: "local";
|
|
167
168
|
preview: "preview";
|
|
168
169
|
published: "published";
|
|
169
|
-
local: "local";
|
|
170
170
|
}>;
|
|
171
171
|
origin: z.ZodString;
|
|
172
172
|
parentOrigin: z.ZodString;
|
|
@@ -187,12 +187,12 @@ export declare const artifactLocalDevSessionSchema: z.ZodObject<{
|
|
|
187
187
|
sourceRevision: z.ZodOptional<z.ZodString>;
|
|
188
188
|
revision: z.ZodNumber;
|
|
189
189
|
state: z.ZodEnum<{
|
|
190
|
+
offline: "offline";
|
|
190
191
|
failed: "failed";
|
|
191
192
|
starting: "starting";
|
|
192
193
|
compiling: "compiling";
|
|
193
194
|
ready: "ready";
|
|
194
195
|
reconnecting: "reconnecting";
|
|
195
|
-
offline: "offline";
|
|
196
196
|
revoked: "revoked";
|
|
197
197
|
expired: "expired";
|
|
198
198
|
}>;
|
package/dist/sdk-orm.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type OperationExecutor } from '@sequenceholdings/orm/client';
|
|
2
|
+
import { type ArtifactOrmJsonScalars } from './orm-json-scalars.js';
|
|
2
3
|
import { type SequenceApi } from './sdk.js';
|
|
3
4
|
export interface ArtifactOrmExecutorConfig {
|
|
4
5
|
namespace: string;
|
|
@@ -8,6 +9,11 @@ export interface ArtifactOrmExecutorConfig {
|
|
|
8
9
|
sdk?: {
|
|
9
10
|
api: Pick<SequenceApi, 'fetch'>;
|
|
10
11
|
};
|
|
12
|
+
/**
|
|
13
|
+
* `lossless-v1` returns numeric and bigint values as strings instead of JSON numbers.
|
|
14
|
+
* The executor refuses any successful result the host does not acknowledge in that form.
|
|
15
|
+
*/
|
|
16
|
+
jsonScalars?: ArtifactOrmJsonScalars;
|
|
11
17
|
}
|
|
12
18
|
/**
|
|
13
19
|
* Execute persisted operations as the signed-in Artifact user. The host owns
|
|
@@ -15,4 +21,4 @@ export interface ArtifactOrmExecutorConfig {
|
|
|
15
21
|
* Declare the namespace path in capabilities.api.write (queries also use POST).
|
|
16
22
|
* Namespace grants, capabilities, row policies, and write checks still apply.
|
|
17
23
|
*/
|
|
18
|
-
export declare function createArtifactOrmExecutor({ namespace, manifest, sdk }: ArtifactOrmExecutorConfig): OperationExecutor;
|
|
24
|
+
export declare function createArtifactOrmExecutor({ namespace, manifest, sdk, jsonScalars }: ArtifactOrmExecutorConfig): OperationExecutor;
|
package/dist/sdk-orm.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createOperationExecutorWithTransport, OrmClientError } from '@sequenceholdings/orm/client';
|
|
2
|
+
import { assertJsonScalarsAcknowledged, ORM_JSON_SCALARS_HEADER } from './orm-json-scalars.js';
|
|
2
3
|
import { seq } from './sdk.js';
|
|
3
4
|
/**
|
|
4
5
|
* Execute persisted operations as the signed-in Artifact user. The host owns
|
|
@@ -6,16 +7,22 @@ import { seq } from './sdk.js';
|
|
|
6
7
|
* Declare the namespace path in capabilities.api.write (queries also use POST).
|
|
7
8
|
* Namespace grants, capabilities, row policies, and write checks still apply.
|
|
8
9
|
*/
|
|
9
|
-
export function createArtifactOrmExecutor({ namespace, manifest, sdk = seq }) {
|
|
10
|
+
export function createArtifactOrmExecutor({ namespace, manifest, sdk = seq, jsonScalars }) {
|
|
10
11
|
if (!sdk || typeof sdk.api?.fetch !== 'function') {
|
|
11
12
|
throw new OrmClientError('Artifact ORM requires the authenticated Artifact Studio host; open the deployed artifact or its Preview');
|
|
12
13
|
}
|
|
13
14
|
return createOperationExecutorWithTransport({
|
|
14
15
|
namespace,
|
|
15
16
|
manifest,
|
|
16
|
-
transport: ({ namespace: target, op, variables }) =>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
transport: async ({ namespace: target, op, variables, idempotencyKey }) => {
|
|
18
|
+
const response = await sdk.api.fetch(`/api/data/v2/${target}`, {
|
|
19
|
+
method: 'POST',
|
|
20
|
+
body: { op, variables, ...(idempotencyKey === undefined ? {} : { idempotencyKey }) },
|
|
21
|
+
...(jsonScalars ? { headers: { [ORM_JSON_SCALARS_HEADER]: jsonScalars } } : {}),
|
|
22
|
+
});
|
|
23
|
+
if (response.ok)
|
|
24
|
+
assertJsonScalarsAcknowledged({ requested: jsonScalars, acknowledged: response.headers?.[ORM_JSON_SCALARS_HEADER], status: response.status });
|
|
25
|
+
return response;
|
|
26
|
+
},
|
|
20
27
|
});
|
|
21
28
|
}
|
package/dist/sdk.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type StartStorageUpload, type StorageUploadSession } from '@sequenceholdings/storage';
|
|
2
2
|
export { createArtifactOrmExecutor, type ArtifactOrmExecutorConfig } from './sdk-orm.js';
|
|
3
|
+
export type { ArtifactOrmJsonScalars } from './orm-json-scalars.js';
|
|
3
4
|
export interface SequenceStorageOptions {
|
|
4
5
|
signal?: AbortSignal;
|
|
5
6
|
timeoutMs?: number;
|
|
@@ -48,6 +49,54 @@ export interface SequenceApi {
|
|
|
48
49
|
patch<TBody = unknown>(path: string, body?: unknown): Promise<TBody>;
|
|
49
50
|
delete<TBody = unknown>(path: string, body?: unknown): Promise<TBody>;
|
|
50
51
|
}
|
|
52
|
+
export type SequenceOfflineRequestMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
53
|
+
export interface SequenceOfflineRequest {
|
|
54
|
+
method: SequenceOfflineRequestMethod;
|
|
55
|
+
path: string;
|
|
56
|
+
body?: unknown;
|
|
57
|
+
headers?: Record<string, string>;
|
|
58
|
+
}
|
|
59
|
+
export interface SequenceOfflineConnectorExecution<TBody = unknown> {
|
|
60
|
+
request: SequenceOfflineRequest;
|
|
61
|
+
/**
|
|
62
|
+
* Invoke the authenticated Artifact Studio bridge. Authentication remains
|
|
63
|
+
* host-owned and is never exposed to the connector or durable storage.
|
|
64
|
+
*/
|
|
65
|
+
network: (request: SequenceOfflineRequest) => Promise<SequenceApiFetchResponse<TBody>>;
|
|
66
|
+
}
|
|
67
|
+
export interface SequenceOfflineNetwork {
|
|
68
|
+
execute<TBody = unknown>(request: SequenceOfflineRequest): Promise<SequenceApiFetchResponse<TBody>>;
|
|
69
|
+
}
|
|
70
|
+
export interface SequenceOfflineRequestConnector {
|
|
71
|
+
execute<TBody = unknown>(execution: SequenceOfflineConnectorExecution<TBody>): Promise<SequenceApiFetchResponse<TBody>>;
|
|
72
|
+
/**
|
|
73
|
+
* Receives a capability-gated bridge executor for durable outbox replay.
|
|
74
|
+
* It carries no bearer token and remains subject to the active manifest.
|
|
75
|
+
*/
|
|
76
|
+
attach?(context: {
|
|
77
|
+
network: SequenceOfflineNetwork;
|
|
78
|
+
}): void | (() => void);
|
|
79
|
+
}
|
|
80
|
+
export interface SequenceOffline {
|
|
81
|
+
/**
|
|
82
|
+
* Install the artifact's request policy beneath seq.api. Returns a disposer
|
|
83
|
+
* that restores the network-only default when it still owns registration.
|
|
84
|
+
*/
|
|
85
|
+
registerConnector(registration: {
|
|
86
|
+
connector: SequenceOfflineRequestConnector;
|
|
87
|
+
}): () => void;
|
|
88
|
+
/** Cache the current artifact shell on this device after the user's opt-in. */
|
|
89
|
+
enroll(options?: {
|
|
90
|
+
maxAgeHours?: number;
|
|
91
|
+
}): Promise<void>;
|
|
92
|
+
/** Remove this artifact's cached shell. App-owned data should be wiped too. */
|
|
93
|
+
remove(): Promise<void>;
|
|
94
|
+
status(): Promise<{
|
|
95
|
+
enabled: boolean;
|
|
96
|
+
enrolled: boolean;
|
|
97
|
+
expiresAt?: number;
|
|
98
|
+
}>;
|
|
99
|
+
}
|
|
51
100
|
export interface SequenceFunctions {
|
|
52
101
|
invoke<TOutput = unknown>(id: string, params?: Record<string, unknown>, traceAction?: {
|
|
53
102
|
id: string;
|
|
@@ -135,6 +184,7 @@ export interface SequenceHost {
|
|
|
135
184
|
export interface SequenceArtifactSdk {
|
|
136
185
|
storage: SequenceStorage;
|
|
137
186
|
api: SequenceApi;
|
|
187
|
+
offline: SequenceOffline;
|
|
138
188
|
ai: {
|
|
139
189
|
fetch(path: string, options?: SequenceApiFetchOptions): Promise<Response>;
|
|
140
190
|
};
|
|
@@ -211,6 +261,73 @@ export declare function createArtifactStorageClient(sdk?: SequenceArtifactSdk):
|
|
|
211
261
|
versionId: string | null;
|
|
212
262
|
maxBytes: number;
|
|
213
263
|
}>;
|
|
264
|
+
startBatch: (items: StartStorageUpload[]) => Promise<{
|
|
265
|
+
items: {
|
|
266
|
+
id: string;
|
|
267
|
+
fileId: string;
|
|
268
|
+
uploadUrl: string | null;
|
|
269
|
+
expiresAt: string;
|
|
270
|
+
state: "pending" | "complete" | "aborted";
|
|
271
|
+
versionId: string | null;
|
|
272
|
+
maxBytes: number;
|
|
273
|
+
}[];
|
|
274
|
+
}>;
|
|
275
|
+
list: () => Promise<{
|
|
276
|
+
items: {
|
|
277
|
+
id: string;
|
|
278
|
+
fileId: string;
|
|
279
|
+
name: string;
|
|
280
|
+
state: "pending" | "complete" | "aborted";
|
|
281
|
+
expiresAt: string;
|
|
282
|
+
maxBytes: number;
|
|
283
|
+
expectedSize: number | null;
|
|
284
|
+
versionId: string | null;
|
|
285
|
+
}[];
|
|
286
|
+
limits: {
|
|
287
|
+
perPrincipal: number;
|
|
288
|
+
perWorkspace: number;
|
|
289
|
+
};
|
|
290
|
+
}>;
|
|
291
|
+
reconcile: (input?: {
|
|
292
|
+
abortIncomplete?: boolean;
|
|
293
|
+
}) => Promise<{
|
|
294
|
+
completed: {
|
|
295
|
+
id: string;
|
|
296
|
+
fileId: string;
|
|
297
|
+
name: string;
|
|
298
|
+
state: "pending" | "complete" | "aborted";
|
|
299
|
+
expiresAt: string;
|
|
300
|
+
maxBytes: number;
|
|
301
|
+
expectedSize: number | null;
|
|
302
|
+
versionId: string | null;
|
|
303
|
+
code: string;
|
|
304
|
+
message: string;
|
|
305
|
+
}[];
|
|
306
|
+
aborted: {
|
|
307
|
+
id: string;
|
|
308
|
+
fileId: string;
|
|
309
|
+
name: string;
|
|
310
|
+
state: "pending" | "complete" | "aborted";
|
|
311
|
+
expiresAt: string;
|
|
312
|
+
maxBytes: number;
|
|
313
|
+
expectedSize: number | null;
|
|
314
|
+
versionId: string | null;
|
|
315
|
+
code: string;
|
|
316
|
+
message: string;
|
|
317
|
+
}[];
|
|
318
|
+
pending: {
|
|
319
|
+
id: string;
|
|
320
|
+
fileId: string;
|
|
321
|
+
name: string;
|
|
322
|
+
state: "pending" | "complete" | "aborted";
|
|
323
|
+
expiresAt: string;
|
|
324
|
+
maxBytes: number;
|
|
325
|
+
expectedSize: number | null;
|
|
326
|
+
versionId: string | null;
|
|
327
|
+
code: string;
|
|
328
|
+
message: string;
|
|
329
|
+
}[];
|
|
330
|
+
}>;
|
|
214
331
|
};
|
|
215
332
|
get: () => Promise<{
|
|
216
333
|
id: string;
|
|
@@ -489,6 +606,15 @@ export declare function createArtifactStorageClient(sdk?: SequenceArtifactSdk):
|
|
|
489
606
|
capabilities: () => Promise<{
|
|
490
607
|
canProvision: boolean;
|
|
491
608
|
uploadMethods: string[];
|
|
609
|
+
pendingUploads: {
|
|
610
|
+
perPrincipal: number;
|
|
611
|
+
perWorkspace: number;
|
|
612
|
+
};
|
|
613
|
+
uploadBatchLimit: number;
|
|
614
|
+
importConcurrency: {
|
|
615
|
+
default: number;
|
|
616
|
+
max: number;
|
|
617
|
+
};
|
|
492
618
|
}>;
|
|
493
619
|
list: (options?: import("@sequenceholdings/storage").StorageListOptions) => Promise<{
|
|
494
620
|
items: {
|