@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.
Files changed (90) hide show
  1. package/README.md +35 -1
  2. package/VERSION-PIN.md +9 -0
  3. package/dist/active-deploy-policy.d.ts +9 -3
  4. package/dist/active-deploy-policy.js +20 -8
  5. package/dist/artifact-env-bindings.d.ts +9 -0
  6. package/dist/artifact-env-bindings.js +32 -0
  7. package/dist/build.js +6 -0
  8. package/dist/cli.js +61 -12
  9. package/dist/deployment-validation.d.ts +2 -0
  10. package/dist/deployment-validation.js +2 -0
  11. package/dist/dev-link.js +28 -2
  12. package/dist/env-binding-scan.d.ts +10 -0
  13. package/dist/env-binding-scan.js +179 -0
  14. package/dist/env-bindings.d.ts +52 -0
  15. package/dist/env-bindings.js +180 -0
  16. package/dist/gateway/control.d.ts +33 -0
  17. package/dist/gateway/control.js +29 -0
  18. package/dist/gateway/hosted-proxy.d.ts +5 -0
  19. package/dist/gateway/hosted-proxy.js +4 -1
  20. package/dist/gateway/lattice-invoke.d.ts +48 -0
  21. package/dist/gateway/lattice-invoke.js +245 -0
  22. package/dist/gateway/lattice-upstream.d.ts +38 -0
  23. package/dist/gateway/lattice-upstream.js +136 -0
  24. package/dist/gateway/server.js +2 -3
  25. package/dist/gateway/session.d.ts +3 -1
  26. package/dist/gateway/session.js +10 -3
  27. package/dist/manifest-next.d.ts +55 -0
  28. package/dist/manifest-next.js +35 -2
  29. package/dist/manifest-static.d.ts +35 -0
  30. package/dist/manifest-static.js +12 -0
  31. package/dist/manifest.d.ts +48 -0
  32. package/dist/next-build.d.ts +2 -1
  33. package/dist/next-build.js +12 -7
  34. package/dist/offline/cache.d.ts +4 -0
  35. package/dist/offline/cache.js +7 -0
  36. package/dist/offline/connector.d.ts +26 -0
  37. package/dist/offline/connector.js +118 -0
  38. package/dist/offline/crypto.d.ts +5 -0
  39. package/dist/offline/crypto.js +24 -0
  40. package/dist/offline/index.d.ts +8 -0
  41. package/dist/offline/index.js +7 -0
  42. package/dist/offline/indexed-db.d.ts +10 -0
  43. package/dist/offline/indexed-db.js +104 -0
  44. package/dist/offline/outbox.d.ts +7 -0
  45. package/dist/offline/outbox.js +46 -0
  46. package/dist/offline/replay.d.ts +25 -0
  47. package/dist/offline/replay.js +192 -0
  48. package/dist/offline/secure-store.d.ts +6 -0
  49. package/dist/offline/secure-store.js +51 -0
  50. package/dist/offline/types.d.ts +162 -0
  51. package/dist/offline/types.js +1 -0
  52. package/dist/orm-json-scalars.d.ts +21 -0
  53. package/dist/orm-json-scalars.js +21 -0
  54. package/dist/runtime-contracts.d.ts +7 -7
  55. package/dist/sdk-orm.d.ts +7 -1
  56. package/dist/sdk-orm.js +12 -5
  57. package/dist/sdk.d.ts +126 -0
  58. package/dist/server/broker-contract.d.ts +191 -5
  59. package/dist/server/broker-contract.js +142 -1
  60. package/dist/server/client.d.ts +60 -12
  61. package/dist/server/client.js +143 -20
  62. package/dist/server/errors.d.ts +26 -0
  63. package/dist/server/errors.js +29 -0
  64. package/dist/server/managed-server-path.d.ts +6 -0
  65. package/dist/server/managed-server-path.js +14 -0
  66. package/dist/server/processes.d.ts +290 -0
  67. package/dist/server/processes.js +56 -0
  68. package/dist/server/request-context.d.ts +6 -0
  69. package/dist/server/request-context.js +10 -1
  70. package/dist/server.d.ts +5 -1
  71. package/dist/server.js +1 -0
  72. package/dist/source-resolver.d.ts +9 -2
  73. package/dist/source-resolver.js +55 -8
  74. package/dist/templates/nextjs/AGENTS.md +10 -0
  75. package/dist/templates/nextjs/CLAUDE.md +1 -0
  76. package/dist/templates/nextjs/README.md +88 -0
  77. package/dist/templates/react-vite/AGENTS.md +8 -88
  78. package/dist/templates/react-vite/CLAUDE.md +0 -6
  79. package/dist/templates/react-vite/package.json +1 -1
  80. package/dist/templates/react-vite/src/App.tsx +37 -14
  81. package/dist/templates/react-vite/src/styles.css +10 -0
  82. package/package.json +7 -3
  83. package/templates/nextjs/AGENTS.md +10 -0
  84. package/templates/nextjs/CLAUDE.md +1 -0
  85. package/templates/nextjs/README.md +88 -0
  86. package/templates/react-vite/AGENTS.md +8 -88
  87. package/templates/react-vite/CLAUDE.md +0 -6
  88. package/templates/react-vite/package.json +1 -1
  89. package/templates/react-vite/src/App.tsx +37 -14
  90. 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 }) => sdk.api.fetch(`/api/data/v2/${target}`, {
17
- method: 'POST',
18
- body: { op, variables },
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: {