@standards/client 0.0.0-stage → 1.0.0-alpha.382

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.
@@ -0,0 +1,439 @@
1
+
2
+ import { r as MultipartRequestOptions, s as TransportConfig, t as HttpTransport } from "./http-transport-DBgedLFQ.mjs";
3
+ import { AggregateRecordsOptions, ContentViewDefinition, DocumentFile, ExtractRecord, ExtractRecordInputStrict, ExtractRecordUpdateStrict, FilterRule, ObjectBuilderLike, ObjectBuilderLike as ObjectBuilderLike$1, ObjectDefinition, RecordAccessRole, RecordAggregates, RecordAudience, RuleValue, SchemaGroupPresentation, SchemaSourceResolution, ViewDeclaration } from "@standards/schema";
4
+ //#region src/define-schema-source.d.ts
5
+ /**
6
+ * `@standards/constants` (the home of `IconName`) is not a dependency of this
7
+ * package; deriving the type from `SchemaGroupPresentation` avoids adding one
8
+ * just for a type alias.
9
+ */
10
+ type IconName = NonNullable<SchemaGroupPresentation["icon"]>;
11
+ type ViewInput = ContentViewDefinition | ViewDeclaration | {
12
+ build(): ContentViewDefinition | ViewDeclaration;
13
+ };
14
+ interface SchemaSourceConfig<TObjects extends readonly ObjectBuilderLike[]> {
15
+ /**
16
+ * Slug identity of the source, required to sync. Write it by hand, or derive
17
+ * it with `sourceIdFromPackageName(packageJson.name)`.
18
+ */
19
+ id?: string;
20
+ objects: TObjects;
21
+ views?: ViewInput[];
22
+ label?: string;
23
+ icon?: IconName;
24
+ }
25
+ /** What `defineSchemaSource` returns: the declaration only — nothing is built until it is resolved. */
26
+ interface SchemaSource<TObjects extends readonly ObjectBuilderLike[] = readonly ObjectBuilderLike[]> {
27
+ readonly id: string | null;
28
+ /** The builders, kept for type inference of the typed client (`db.<camelCaseName>`). */
29
+ readonly builders: TObjects;
30
+ readonly views: readonly ViewInput[];
31
+ readonly label: string | null;
32
+ readonly icon: IconName | null;
33
+ }
34
+ /** A source built, validated and hashed — what a sync sends. */
35
+ interface ResolvedSchemaSource {
36
+ id: string | null;
37
+ /** sha256 hex of `canonicalStringify({ objects, views })` — the same digest the server recomputes. */
38
+ hash: string;
39
+ objects: ObjectDefinition[];
40
+ views: ContentViewDefinition[];
41
+ label: string | null;
42
+ icon: IconName | null;
43
+ }
44
+ /** sha256 hex over the canonical JSON, with Web Crypto (Node >= 20, Edge, browsers). */
45
+ declare function hashSchemaSource(payload: {
46
+ objects: ObjectDefinition[];
47
+ views: ContentViewDefinition[];
48
+ }): Promise<string>;
49
+ /** Declares the schema an external codebase owns. Does no work: see `resolveSchemaSource`. */
50
+ declare function defineSchemaSource<const TObjects extends readonly ObjectBuilderLike[]>(config: SchemaSourceConfig<TObjects>): SchemaSource<TObjects>;
51
+ /** Builds, validates and hashes a source once; later calls share the same promise. */
52
+ declare function resolveSchemaSource(source: SchemaSource): Promise<ResolvedSchemaSource>;
53
+ /** `@acme/crm` -> `acme-crm`; refuses a name the server would refuse as a source id. */
54
+ declare function sourceIdFromPackageName(packageName: string): string;
55
+ //#endregion
56
+ //#region src/files/file-input.d.ts
57
+ /**
58
+ * What the files and documents methods upload: a `File` (or any `Blob` carrying
59
+ * a `name`) with a non-empty filename and MIME type. The server checks the MIME
60
+ * type, the extension and the file signature against each other, so all three
61
+ * travel with the bytes. A `Buffer` or a path is not an input: wrap the bytes in
62
+ * `new File([bytes], "name.png", { type: "image/png" })`.
63
+ */
64
+ type FileInput = Blob & {
65
+ readonly name: string;
66
+ };
67
+ /**
68
+ * The timeout of one upload's request, in ms (#4741). A large file on a slow
69
+ * link outlives the client's `timeoutMs` (30 s by default) and surfaces as a
70
+ * connection failure, possibly after the server stored it — so raise it for
71
+ * large uploads rather than retrying a timed-out attach.
72
+ */
73
+ interface UploadTimeoutOption {
74
+ timeoutMs?: number;
75
+ }
76
+ //#endregion
77
+ //#region src/files/documents-api.d.ts
78
+ interface AttachToRecordInput extends UploadTimeoutOption {
79
+ objectName: string;
80
+ recordId: string;
81
+ /** The record's `document` attribute; the server defaults to `attachments`. */
82
+ attributeName?: string;
83
+ /** Append to this existing document's pack instead of creating a document. */
84
+ documentId?: string;
85
+ /** The new document's title; the server defaults to the filename without its extension. */
86
+ title?: string;
87
+ /**
88
+ * The bytes to upload, private, in the same request — the input
89
+ * `files.upload` takes. The attach route takes one file per call: append
90
+ * more by passing the returned `document.id` as `documentId`. An
91
+ * already-uploaded file is not an input, so a public upload can never end up
92
+ * in a document.
93
+ */
94
+ file: FileInput;
95
+ }
96
+ interface AttachToRecordResult {
97
+ document: {
98
+ id: string;
99
+ title: string;
100
+ };
101
+ file: DocumentFile;
102
+ /** `created`: a new document on the record; `appended`: added to `documentId`'s pack. */
103
+ action: "created" | "appended";
104
+ }
105
+ interface DocumentsApi {
106
+ /**
107
+ * Upload a file and attach it to a record's document attribute in ONE
108
+ * multipart `POST /records/:object/:id/documents/attach`. The server
109
+ * validates the file against the attribute and deletes the upload if the
110
+ * attach fails, so an error never leaves an orphaned file.
111
+ */
112
+ attachToRecord(input: AttachToRecordInput): Promise<AttachToRecordResult>;
113
+ /** The document's files in pack order (`GET /documents/:id/files`). */
114
+ listFiles(documentId: string): Promise<DocumentFile[]>;
115
+ }
116
+ /** The two verbs this module needs, typed non-generically so a stub satisfies it. */
117
+ interface DocumentsTransport {
118
+ get(path: string): Promise<unknown>;
119
+ postMultipart(path: string, form: FormData, options?: MultipartRequestOptions): Promise<unknown>;
120
+ }
121
+ declare function createDocumentsApi(transport: DocumentsTransport): DocumentsApi;
122
+ //#endregion
123
+ //#region src/files/files-api.d.ts
124
+ interface UploadFileBase extends UploadTimeoutOption {
125
+ file: FileInput;
126
+ /** Stored as the file's folder (`folderPath` on `POST /files/upload`). */
127
+ folderPath?: string;
128
+ }
129
+ /** Anyone holding the returned `publicUrl` can open the file. A public file never joins a document. */
130
+ interface UploadPublicFileInput extends UploadFileBase {
131
+ public: true;
132
+ }
133
+ /** The default: readable through a signed URL from `getDownloadUrl`. */
134
+ interface UploadPrivateFileInput extends UploadFileBase {
135
+ public?: false;
136
+ }
137
+ type UploadFileInput = UploadPublicFileInput | UploadPrivateFileInput;
138
+ interface UploadedFileBase {
139
+ id: string;
140
+ /** The stored (sanitized) filename. */
141
+ name: string;
142
+ mimeType: string;
143
+ size: number;
144
+ }
145
+ interface PublicUploadedFile extends UploadedFileBase {
146
+ isPublic: true;
147
+ /** `{publicFilesUrl}/{id}`: permanent, and never carries a credential. */
148
+ publicUrl: string;
149
+ }
150
+ interface PrivateUploadedFile extends UploadedFileBase {
151
+ isPublic: false;
152
+ publicUrl?: never;
153
+ }
154
+ /** Discriminated on `isPublic`: only the public branch has a `publicUrl`. */
155
+ type UploadedFile = PublicUploadedFile | PrivateUploadedFile;
156
+ interface FilesApi {
157
+ /** One multipart `POST /files/upload`. */
158
+ upload(input: UploadPublicFileInput): Promise<PublicUploadedFile>;
159
+ upload(input: UploadPrivateFileInput): Promise<PrivateUploadedFile>;
160
+ upload(input: UploadFileInput): Promise<UploadedFile>;
161
+ /** A fresh signed read URL (`GET /files/:id/url`); it expires, so ask again each time. */
162
+ getDownloadUrl(fileId: string): Promise<string>;
163
+ }
164
+ /** The one verb this module needs: the `files` operations. */
165
+ type FilesTransport = Pick<HttpTransport, "call">;
166
+ declare function createFilesApi(transport: FilesTransport): FilesApi;
167
+ //#endregion
168
+ //#region src/object-keys.d.ts
169
+ /** `daily-stats` → `dailyStats`. Object names are kebab-case (enforced by the builder). */
170
+ type CamelCase<S extends string> = S extends `${infer Head}-${infer Tail}` ? `${Head}${Capitalize<CamelCase<Tail>>}` : S;
171
+ //#endregion
172
+ //#region src/records/query.d.ts
173
+ type Attr<TBuilder> = keyof ExtractRecord<TBuilder> & string;
174
+ /**
175
+ * The builder's own attributes keep their exact types (a `select` refuses an
176
+ * option it does not declare); runtime-added custom attributes stay writable
177
+ * through the open index. `ExtractRecordInput`'s own index is typed
178
+ * `CustomAttributeValue`, which has no `Date` member and would reject the very
179
+ * date values the REST API accepts — hence the strict variant plus this index.
180
+ */
181
+ type RecordInput<TBuilder> = ExtractRecordInputStrict<TBuilder> & {
182
+ [key: string]: unknown;
183
+ };
184
+ type RecordUpdate<TBuilder> = ExtractRecordUpdateStrict<TBuilder> & {
185
+ [key: string]: unknown;
186
+ };
187
+ /** What `export()` takes beside its columns. */
188
+ interface RecordsExportOptions {
189
+ /** Export only these records (at most `EXPORT_MAX_IDS`, 20 000). */
190
+ ids?: string[];
191
+ /** BCP 47 locale numbers, dates and headers are written in. Default: the request's. */
192
+ locale?: string;
193
+ /** IANA zone dates are read in. Default: the caller's (`Intl`). */
194
+ timezone?: string;
195
+ /** The tab name the downloaded file is named after (`{object}-{tab}-{date}.csv`). */
196
+ filename?: string;
197
+ }
198
+ /** What `aggregate()` takes: the aggregate contract minus the query, which is this one. */
199
+ type RecordsAggregateOptions = Omit<AggregateRecordsOptions, "query">;
200
+ interface FetchResult<TBuilder> {
201
+ records: ExtractRecord<TBuilder>[];
202
+ total: number | null;
203
+ }
204
+ /** One input `createMany` did not create; `index` is its position in the caller's array. */
205
+ interface CreateManyError {
206
+ index: number;
207
+ error: string;
208
+ }
209
+ interface CreateManyResult<TBuilder> {
210
+ created: ExtractRecord<TBuilder>[];
211
+ errors: CreateManyError[];
212
+ }
213
+ /** One `{ id, data }` pair of `updateMany`; `data` is typed like `update`'s patch. */
214
+ interface UpdateManyEntry<TBuilder> {
215
+ id: string;
216
+ data: RecordUpdate<TBuilder>;
217
+ }
218
+ /** One entry `updateMany` did not update. */
219
+ /**
220
+ * One id `updateMany` did not update. `code` is the server's `SchemaErrorCode`
221
+ * when the runtime raised the refusal (`SCHEMA_FORBIDDEN`,
222
+ * `SCHEMA_SYSTEM_ENTITY_IMMUTABLE`, …); a database-side rejection carries its message only.
223
+ */
224
+ interface UpdateManyError {
225
+ id: string;
226
+ error: string;
227
+ code?: string;
228
+ }
229
+ interface UpdateManyResult<TBuilder> {
230
+ updated: ExtractRecord<TBuilder>[];
231
+ errors: UpdateManyError[];
232
+ }
233
+ /**
234
+ * One id `deleteMany` did not delete. `code` is the server's `SchemaErrorCode`
235
+ * when the runtime raised the refusal (`SCHEMA_FORBIDDEN`,
236
+ * `SCHEMA_RECORD_NOT_FOUND`, …); a database-side rejection carries its message only.
237
+ */
238
+ interface DeleteManyError {
239
+ id: string;
240
+ error: string;
241
+ code?: string;
242
+ }
243
+ interface DeleteManyResult {
244
+ deleted: string[];
245
+ errors: DeleteManyError[];
246
+ }
247
+ interface RecordsQuery<TBuilder> {
248
+ eq(attribute: Attr<TBuilder>, value: RuleValue): RecordsQuery<TBuilder>;
249
+ neq(attribute: Attr<TBuilder>, value: RuleValue): RecordsQuery<TBuilder>;
250
+ /** Appends rules as they are: any operator, a qualified `property`, `exists`, dynamic values. */
251
+ where(...rules: (Omit<FilterRule, "attribute"> & {
252
+ attribute: Attr<TBuilder>;
253
+ })[]): RecordsQuery<TBuilder>;
254
+ gt(attribute: Attr<TBuilder>, value: RuleValue): RecordsQuery<TBuilder>;
255
+ gte(attribute: Attr<TBuilder>, value: RuleValue): RecordsQuery<TBuilder>;
256
+ lt(attribute: Attr<TBuilder>, value: RuleValue): RecordsQuery<TBuilder>;
257
+ lte(attribute: Attr<TBuilder>, value: RuleValue): RecordsQuery<TBuilder>;
258
+ contains(attribute: Attr<TBuilder>, value: RuleValue): RecordsQuery<TBuilder>;
259
+ notContains(attribute: Attr<TBuilder>, value: RuleValue): RecordsQuery<TBuilder>;
260
+ startsWith(attribute: Attr<TBuilder>, value: string): RecordsQuery<TBuilder>;
261
+ endsWith(attribute: Attr<TBuilder>, value: string): RecordsQuery<TBuilder>;
262
+ in(attribute: Attr<TBuilder>, values: string[]): RecordsQuery<TBuilder>;
263
+ notIn(attribute: Attr<TBuilder>, values: string[]): RecordsQuery<TBuilder>;
264
+ isEmpty(attribute: Attr<TBuilder>): RecordsQuery<TBuilder>;
265
+ isNotEmpty(attribute: Attr<TBuilder>): RecordsQuery<TBuilder>;
266
+ or(): RecordsQuery<TBuilder>;
267
+ orderBy(attribute: Attr<TBuilder>, direction?: "asc" | "desc"): RecordsQuery<TBuilder>;
268
+ limit(count: number): RecordsQuery<TBuilder>;
269
+ offset(count: number): RecordsQuery<TBuilder>;
270
+ search(query: string): RecordsQuery<TBuilder>;
271
+ /**
272
+ * `POST /records/<object>/export`: this query's search, filters and sorts as
273
+ * a CSV with the given attributes as columns, in order. Resolves to the
274
+ * unread `Response` (`text/csv`, UTF-8 BOM, CRLF) so a large export can be
275
+ * streamed; a refusal (`EXPORT_TOO_LARGE`, validation) rejects before any byte.
276
+ * `ids` restricts it to those records; `timezone` (default: the caller's) is
277
+ * the zone dates are read in; `filename` is the tab name the file is named after.
278
+ */
279
+ export(columns: string[], options?: RecordsExportOptions): Promise<Response>;
280
+ /**
281
+ * `POST /records/<object>/aggregate`: one measure over this query's records,
282
+ * optionally grouped and compared with the previous period. The query's
283
+ * filters and relation scope are measured; its sorts and limit are ignored,
284
+ * and a search is refused (`AGGREGATE_SEARCH_UNSUPPORTED`). `timezone`
285
+ * defaults to the caller's.
286
+ */
287
+ aggregate(options: RecordsAggregateOptions): Promise<RecordAggregates>;
288
+ fetch(): Promise<FetchResult<TBuilder>>;
289
+ /**
290
+ * Every matching record, walked in pages of {@link RECORDS_PAGE_SIZE} with
291
+ * this query's filters, sorts and search while the response says
292
+ * `page.hasMore`, resuming at its `nextOffset`. An
293
+ * explicit `limit(n)` caps the total, an explicit `offset(k)` is where the
294
+ * walk starts. A page that fails rejects the whole call.
295
+ */
296
+ all(): Promise<ExtractRecord<TBuilder>[]>;
297
+ single(): Promise<ExtractRecord<TBuilder> | null>;
298
+ get(id: string): Promise<ExtractRecord<TBuilder>>;
299
+ create(input: RecordInput<TBuilder>): Promise<ExtractRecord<TBuilder>>;
300
+ update(id: string, patch: RecordUpdate<TBuilder>): Promise<ExtractRecord<TBuilder>>;
301
+ delete(id: string): Promise<void>;
302
+ /**
303
+ * `POST /records/<object>/bulk-create`, 100 inputs per request, sent one after
304
+ * another. A refused input is reported in `errors` (never thrown); a failed
305
+ * request rejects, and the chunks before it stay created. Every record is
306
+ * workspace-visible: the route takes no visibility.
307
+ */
308
+ createMany(inputs: readonly RecordInput<TBuilder>[]): Promise<CreateManyResult<TBuilder>>;
309
+ /** `POST /records/<object>/bulk-update`, chunked and reported like `createMany`. */
310
+ updateMany(entries: readonly UpdateManyEntry<TBuilder>[]): Promise<UpdateManyResult<TBuilder>>;
311
+ /** `POST /records/<object>/bulk-delete`, chunked and reported like `createMany`. */
312
+ deleteMany(ids: readonly string[]): Promise<DeleteManyResult>;
313
+ /** Who can reach this private record beyond its owner: `GET /records/<object>/<id>/access`. */
314
+ listAccess(id: string): Promise<RecordAudience>;
315
+ /** Share a private record you own or edit: `PUT /records/<object>/<id>/access/<actorId>`. */
316
+ grantAccess(id: string, actorId: string, role: RecordAccessRole): Promise<RecordAudience>;
317
+ /** Remove your manual share: `DELETE /records/<object>/<id>/access/<actorId>`. */
318
+ revokeAccess(id: string, actorId: string): Promise<RecordAudience>;
319
+ /** Make a shared record private again — every manual share at once: `DELETE /records/<object>/<id>/access`. */
320
+ clearAccess(id: string): Promise<RecordAudience>;
321
+ }
322
+ /**
323
+ * The builder shape `from(objectName: string)` stands in for: no declared
324
+ * attributes, so `ExtractRecord` resolves to an open record and `records` is a
325
+ * usable `Record<string, unknown> & RecordMetadata` array instead of `never[]`.
326
+ * `build()` returns `never` because there is no definition to build — the
327
+ * string overload never calls it.
328
+ */
329
+ interface UntypedBuilder {
330
+ readonly _types: {
331
+ name: string;
332
+ record: Record<string, unknown>;
333
+ input: Record<string, unknown>;
334
+ update: Record<string, unknown>;
335
+ };
336
+ build(): never;
337
+ }
338
+ /** What `standards.from("object-name")` hands back. */
339
+ type UntypedRecordsQuery = RecordsQuery<UntypedBuilder>;
340
+ /**
341
+ * The verbs this module needs, typed non-generically: the real `Transport`
342
+ * satisfies it, and so does a hand-rolled stub, which a `Pick` of the generic
343
+ * signatures would reject. `postRaw` only serves `export()`, which refuses
344
+ * when a stub leaves it out. Each path is its contract operation's
345
+ * (`buildOperationPath`, every parameter one encoded segment); the verbs stay
346
+ * the transport's.
347
+ */
348
+ interface RecordsTransport {
349
+ get(path: string): Promise<unknown>;
350
+ post(path: string, body?: unknown): Promise<unknown>;
351
+ postRaw?(path: string, body: unknown): Promise<Response>;
352
+ put(path: string, body?: unknown): Promise<unknown>;
353
+ delete(path: string): Promise<unknown>;
354
+ }
355
+ /** A builder gives typed records; a bare object name is the untyped escape hatch. */
356
+ declare function createRecordsQuery<TBuilder extends ObjectBuilderLike$1>(transport: RecordsTransport, target: TBuilder): RecordsQuery<TBuilder>;
357
+ declare function createRecordsQuery(transport: RecordsTransport, target: string): UntypedRecordsQuery;
358
+ //#endregion
359
+ //#region src/schema-sync.d.ts
360
+ interface SchemaSourceSummary {
361
+ sourceId: string;
362
+ hash: string;
363
+ appliedAt: string;
364
+ objectNames: string[];
365
+ /** Absent on an older server that predates presentation; treated as "no presentation". */
366
+ label?: string | null;
367
+ icon?: string | null;
368
+ }
369
+ interface SyncResult {
370
+ applied: boolean;
371
+ hash: string;
372
+ objects?: {
373
+ created: number;
374
+ updated: number;
375
+ deleted: number;
376
+ };
377
+ views?: {
378
+ created: number;
379
+ updated: number;
380
+ adopted: number;
381
+ released: number;
382
+ };
383
+ }
384
+ /**
385
+ * What a sync carries besides the source itself.
386
+ *
387
+ * `resolutions` resolve the renames and retypes the server refuses as
388
+ * ambiguous (`SCHEMA_AMBIGUOUS_CHANGE`), which names the exact entries to
389
+ * send. They travel outside the hash: a source whose hash is already applied
390
+ * is not pushed, and the resolutions with it. A server older than
391
+ * `resolutions` answers 400 `Unknown source payload fields` — upgrade the
392
+ * client and the server together.
393
+ */
394
+ interface SyncOptions {
395
+ resolutions?: SchemaSourceResolution[];
396
+ }
397
+ /**
398
+ * The two verbs a sync needs, typed non-generically: the real `Transport`
399
+ * satisfies it, and so does a hand-rolled stub, which a `Pick` of the generic
400
+ * signatures would reject.
401
+ */
402
+ interface SyncTransport {
403
+ get(path: string): Promise<unknown>;
404
+ put(path: string, body?: unknown): Promise<unknown>;
405
+ }
406
+ /** GET the remote summary; PUT when the hash or the presentation differs, or the source was never pushed. */
407
+ declare function syncSchemaSource(transport: SyncTransport, declared: SchemaSource, options?: SyncOptions): Promise<SyncResult>;
408
+ //#endregion
409
+ //#region src/create-standards.d.ts
410
+ type NameOf<B> = B extends {
411
+ _types: {
412
+ name: infer N extends string;
413
+ };
414
+ } ? N : never;
415
+ /** One typed query per object of a source, keyed by the camelCase of its name. */
416
+ type ObjectsOf<TObjects extends readonly ObjectBuilderLike$1[]> = { readonly [B in TObjects[number] as CamelCase<NameOf<B>>]: RecordsQuery<B>; };
417
+ interface Standards {
418
+ schema: {
419
+ sync(source: SchemaSource, options?: SyncOptions): Promise<SyncResult>;
420
+ };
421
+ /** Untyped access to an object the code does not declare (created at runtime). */
422
+ from(objectName: string): UntypedRecordsQuery;
423
+ /** Upload files (private or public) and read them back through signed URLs. */
424
+ files: FilesApi;
425
+ /** Attach uploads to a record's document attribute and list a document's files. */
426
+ documents: DocumentsApi;
427
+ }
428
+ /**
429
+ * The options `createStandards` takes. Every field of `TransportConfig` is
430
+ * optional here: on the server a missing `baseUrl` / `apiKey` is read from
431
+ * `STANDARDS_API_URL` / `STANDARDS_API_KEY`, and an explicit value always wins.
432
+ */
433
+ type StandardsConfig = Partial<TransportConfig>;
434
+ declare function createStandards<const TObjects extends readonly ObjectBuilderLike$1[]>(config: StandardsConfig & {
435
+ schema: SchemaSource<TObjects>;
436
+ }): Standards & ObjectsOf<TObjects>;
437
+ declare function createStandards(config?: StandardsConfig): Standards;
438
+ //#endregion
439
+ export { UploadFileInput as A, FileInput as B, UpdateManyResult as C, FilesTransport as D, FilesApi as E, AttachToRecordInput as F, SchemaSource as G, IconName as H, AttachToRecordResult as I, defineSchemaSource as J, SchemaSourceConfig as K, DocumentsApi as L, UploadPublicFileInput as M, UploadedFile as N, PrivateUploadedFile as O, createFilesApi as P, DocumentsTransport as R, UpdateManyError as S, CamelCase as T, ObjectBuilderLike$1 as U, UploadTimeoutOption as V, ResolvedSchemaSource as W, resolveSchemaSource as X, hashSchemaSource as Y, sourceIdFromPackageName as Z, RecordsExportOptions as _, SchemaSourceSummary as a, UntypedRecordsQuery as b, syncSchemaSource as c, DeleteManyError as d, DeleteManyResult as f, RecordsAggregateOptions as g, RecordUpdate as h, createStandards as i, UploadPrivateFileInput as j, PublicUploadedFile as k, CreateManyError as l, RecordInput as m, Standards as n, SyncOptions as o, FetchResult as p, ViewInput as q, StandardsConfig as r, SyncResult as s, ObjectsOf as t, CreateManyResult as u, RecordsQuery as v, createRecordsQuery as w, UpdateManyEntry as x, UntypedBuilder as y, createDocumentsApi as z };
@@ -0,0 +1,2 @@
1
+ /*! © 2025-2026 AND YOU CREATE SAS (RCS Paris 940 190 614). Proprietary — see LICENSE (Standards SDK License 1.0). */
2
+ const e=require("./http-transport-DHbErYa4.js");let t=require("@standards/schema"),n=require("@standards/schema/api");function objectKeyOf(e){return e.replace(/-([a-z0-9])/g,(e,t)=>t.toUpperCase())}const r=new Set([`from`,`files`,`documents`,`schema`]);function assertObjectKeys(t){let n=new Map;for(let i of t){if(i.includes(`--`)||i.endsWith(`-`))throw new e.h(`Object "${i}" has a doubled or trailing hyphen, which has no client key. Rename the object.`);let t=objectKeyOf(i);if(r.has(t))throw new e.h(`Object "${i}" maps to the client key "${t}", which is reserved. Rename the object.`);let a=n.get(t);if(a!==void 0&&a!==i)throw new e.h(`Objects "${a}" and "${i}" both map to the client key "${t}". Rename one of them.`);n.set(t,i)}}function buildView(e){let n=`build`in e&&typeof e.build==`function`?e.build():e,r=`kind`in n&&n.kind===`view`?n.definition:n,i=t.contentViewDefinitionSchema.safeParse(r);if(i.success)return i.data;let a=typeof r==`object`&&r&&`name`in r?String(r.name):`(unnamed)`,o=t.ValidationError.fromZodErrors(i.error.issues.map(e=>({path:e.path.map(String),message:e.message})));throw new t.ValidationError(`View "${a}" is invalid. ${o.message}`,o.errors)}async function hashSchemaSource(e){let n=new TextEncoder().encode((0,t.canonicalStringify)(e)),r=await crypto.subtle.digest(`SHA-256`,n);return Array.from(new Uint8Array(r),e=>e.toString(16).padStart(2,`0`)).join(``)}function assertObjectNames(e){let n=new Set;for(let r of e){if(n.has(r))throw new t.DuplicateError(`object`,r);n.add(r)}assertObjectKeys(e)}function defineSchemaSource(e){return{id:e.id??null,builders:e.objects,views:e.views??[],label:e.label??null,icon:e.icon??null}}const i=new WeakMap;async function resolveOnce(e){e.id!==null&&(0,t.assertSchemaSourceId)(e.id);let n=(0,t.parseSchemaGroupPresentation)({label:e.label??void 0,icon:e.icon??void 0}),r=e.builders.map(e=>e.build());assertObjectNames(r.map(e=>e.name));let i=e.views.map(buildView);return{id:e.id,hash:await hashSchemaSource({objects:r,views:i}),objects:r,views:i,label:n.label??null,icon:n.icon??null}}function resolveSchemaSource(e){let t=i.get(e);return t===void 0&&(t=resolveOnce(e),i.set(e,t)),t}function sourceIdFromPackageName(n){let r=n.toLowerCase().replace(/^@/,``).replace(/\//g,`-`);try{(0,t.assertSchemaSourceId)(r)}catch{throw new e.h(`package.json name "${n}" is not a usable schema source id. Add id: "<lowercase-slug>" to defineSchemaSource.`)}return r}function assertTimeout(e){if(e!==void 0&&!(Number.isFinite(e)&&e>0))throw new t.ValidationError(`timeoutMs must be a positive number of milliseconds`,[{path:[`timeoutMs`],message:`Expected a positive, finite number`}])}function assertFileInput(e,n){if(!(e instanceof Blob))throw new t.ValidationError(`${n} must be a Blob or File`,[{path:[n],message:`Expected a Blob or File`}]);let r=e.name;if(typeof r!=`string`||r===``)throw new t.ValidationError(`${n} needs a filename`,[{path:[n,`name`],message:`Expected a non-empty filename`}]);if(e.type===``)throw new t.ValidationError(`${n} "${r}" needs a MIME type`,[{path:[n,`type`],message:`Expected a non-empty MIME type`}])}function reviveDocumentFile(e){return{...e,processedAt:e.processedAt===null?null:new Date(e.processedAt)}}function createDocumentsApi(e){async function attachToRecord(t){let{file:r}=t;assertFileInput(r,`file`),assertTimeout(t.timeoutMs);let i=(0,n.buildOperationPath)(n.recordsOperations.attachDocument,{objectName:t.objectName,id:t.recordId}),a=new FormData;a.append(`files`,r,r.name),t.attributeName!==void 0&&a.append(`attributeName`,t.attributeName),t.documentId!==void 0&&a.append(`documentId`,t.documentId),t.title!==void 0&&a.append(`title`,t.title);let o=await e.postMultipart(i,a,{timeoutMs:t.timeoutMs});return{document:{id:o.document.id,title:o.document.title},file:reviveDocumentFile(o.file),action:o.action}}async function listFiles(t){return(await e.get((0,n.buildOperationPath)(n.documentsOperations.files,{id:t}))).map(reviveDocumentFile)}return{attachToRecord,listFiles}}function toUploadedFile(e){let t={id:e.id,name:e.name,mimeType:e.mimeType,size:e.size};return e.isPublic===!0&&typeof e.publicUrl==`string`?{...t,isPublic:!0,publicUrl:e.publicUrl}:{...t,isPublic:!1}}function createFilesApi(e){async function upload(t){assertFileInput(t.file,`file`),assertTimeout(t.timeoutMs);let[r]=await e.call(n.filesOperations.upload,{files:[t.file],public:t.public===!0?`true`:`false`,folderPath:t.folderPath},{timeoutMs:t.timeoutMs});return toUploadedFile(r)}async function getDownloadUrl(t){let{url:r}=await e.call(n.filesOperations.signedUrl,{id:t});return r}return{upload,getDownloadUrl}}const a=[`createdAt`,`updatedAt`,`deletedAt`];function dateAttributeNames(e){let t=new Set;for(let n of e?.attributes??[])n.type===`date`&&t.add(n.name);return t}function isRange(e){return typeof e==`object`&&!!e&&`start`in e&&`end`in e}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function flattenValues(e){let{values:t,...n}=e;return{...n,...isRecord(t)?t:{}}}function toDate(e){return typeof e==`string`?new Date(e):isRange(e)?{start:toDate(e.start),end:toDate(e.end)}:e}function reviveRecord(e,t){let n=dateAttributeNames(e),r=flattenValues(t);for(let e of a)e in r&&(r[e]=toDate(r[e]));for(let e of n)e in r&&(r[e]=toDate(r[e]));return r}function serializeInput(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,t instanceof Date?t.toISOString():t]))}var o=class RecordsQueryImpl extends t.RecordQuery{constructor(e,t,n,r={object:t,combinator:`and`,rules:[],sorts:[]}){super(r),this.transport=e,this.objectName=t,this.definition=n}with(e){return new RecordsQueryImpl(this.transport,this.objectName,this.definition,{...this.state,...e})}body(){let e={};return this.state.search!==void 0&&(e.q=this.state.search),this.state.rules.length>0&&(e.filters={combinator:this.state.combinator,rules:this.state.rules}),this.state.sorts.length>0&&(e.sorts=this.state.sorts),this.state.limit!==void 0&&(e.limit=this.state.limit),this.state.offset!==void 0&&(e.offset=this.state.offset),e}revive(e){return reviveRecord(this.definition,e)}async export(t,r={}){if(!this.transport.postRaw)throw new e.h(`export() needs a transport with postRaw(path, body): Promise<Response>`);let{filters:i,sorts:a}=this.body(),{ids:o,locale:s,filename:c}=r;return await this.transport.postRaw((0,n.buildOperationPath)(n.recordsOperations.export,{objectName:this.objectName}),{q:this.state.search??``,...i?{filters:i}:{},...a?{sorts:a}:{},columns:t,...o?{ids:o}:{},...s?{locale:s}:{},timezone:r.timezone??Intl.DateTimeFormat().resolvedOptions().timeZone,...c?{filename:c}:{}})}async aggregate(e){if(this.state.search!==void 0)throw new t.AggregateValidationError(t.SchemaErrorCode.AGGREGATE_SEARCH_UNSUPPORTED,`An aggregate cannot be narrowed by a search; use filters instead`);let r={...e,query:this.toDefinition(),timezone:e.timezone??Intl.DateTimeFormat().resolvedOptions().timeZone};return await this.transport.post((0,n.buildOperationPath)(n.recordsOperations.aggregate,{objectName:this.objectName}),r)}async fetchPage(){let e=this.state.search===void 0?`list`:`search`,t=await this.transport.post((0,n.buildOperationPath)(n.recordsOperations[e],{objectName:this.objectName}),this.body());return{records:t.data.map(e=>this.revive(e)),page:t.page}}async fetch(){let{records:e,page:t}=await this.fetchPage();return{records:e,total:t.total}}async all(){if(this.state.limit!==void 0&&this.state.limit<0)return(await this.fetch()).records;let e=this.state.limit??1/0,t=[],n=this.state.offset??0;for(;;){let r=Math.min(1e3,e-t.length);if(r<=0)return t;let{records:i,page:a}=await this.with({limit:r,offset:n}).fetchPage();if(t.push(...i),!a.hasMore)return t;let o=a.nextOffset??n+i.length;if(o<=n)return t;n=o}}async single(){let{records:e}=await this.limit(1).fetch();return e[0]??null}async get(e){let t=await this.transport.get((0,n.buildOperationPath)(n.recordsOperations.get,{objectName:this.objectName,id:e}));return this.revive(t)}async create(e){let t=await this.transport.post((0,n.buildOperationPath)(n.recordsOperations.create,{objectName:this.objectName}),{data:serializeInput(e)});return this.revive(t)}async update(e,t){let r=await this.transport.put((0,n.buildOperationPath)(n.recordsOperations.update,{objectName:this.objectName,id:e}),serializeInput(t));return this.revive(r)}async delete(e){await this.transport.delete((0,n.buildOperationPath)(n.recordsOperations.delete,{objectName:this.objectName,id:e}))}async inChunks(e,t){for(let n=0;n<e.length;n+=100)await t(e.slice(n,n+100),n)}async createMany(e){let t={created:[],errors:[]};return await this.inChunks(e,async(e,r)=>{let i=await this.transport.post((0,n.buildOperationPath)(n.recordsOperations.bulkCreate,{objectName:this.objectName}),{records:e.map(serializeInput)});t.created.push(...i.created.map(e=>this.revive(e))),t.errors.push(...i.errors.map(e=>({...e,index:e.index+r})))}),t}async updateMany(e){let t={updated:[],errors:[]};return await this.inChunks(e,async e=>{let r=await this.transport.post((0,n.buildOperationPath)(n.recordsOperations.bulkUpdate,{objectName:this.objectName}),{updates:e.map(({id:e,data:t})=>({id:e,data:serializeInput(t)}))});t.updated.push(...r.updated.map(e=>this.revive(e))),t.errors.push(...r.errors)}),t}async deleteMany(e){let t={deleted:[],errors:[]};return await this.inChunks(e,async e=>{let r=await this.transport.post((0,n.buildOperationPath)(n.recordsOperations.bulkDelete,{objectName:this.objectName}),{ids:e});t.deleted.push(...r.deleted),t.errors.push(...r.errors)}),t}async listAccess(e){return await this.transport.get((0,n.buildOperationPath)(n.recordAccessOperations.list,{objectName:this.objectName,recordId:e}))}async grantAccess(e,t,r){return await this.transport.put((0,n.buildOperationPath)(n.recordAccessOperations.grant,{objectName:this.objectName,recordId:e,actorId:t}),{role:r})}async revokeAccess(e,t){return await this.transport.delete((0,n.buildOperationPath)(n.recordAccessOperations.revoke,{objectName:this.objectName,recordId:e,actorId:t}))}async clearAccess(e){return await this.transport.delete((0,n.buildOperationPath)(n.recordAccessOperations.clear,{objectName:this.objectName,recordId:e}))}};const s=new WeakMap;function definitionOf(e){let t=s.get(e);if(t)return t;let n=e.build();return s.set(e,n),n}function createRecordsQuery(e,t){if(typeof t==`string`)return new o(e,t,null);let n=definitionOf(t);return new o(e,n.name,n)}async function syncSchemaSource(t,n,r={}){let i=await resolveSchemaSource(n);if(i.id===null)throw new e.h(`This schema source has no id. Add id: "<lowercase-slug>" to defineSchemaSource, or derive one with sourceIdFromPackageName(packageJson.name).`);let a=`/schema/sources/${encodeURIComponent(i.id)}`,o;try{o=await t.get(a)}catch(t){if(t instanceof e.g&&t.status===404)o=null;else throw t}if(o?.hash===i.hash&&(i.label===null||(o.label??null)===i.label)&&(i.icon===null||(o.icon??null)===i.icon))return{applied:!1,hash:i.hash};let s={hash:i.hash,objects:i.objects,views:i.views};i.label!==null&&(s.label=i.label),i.icon!==null&&(s.icon=i.icon),r.resolutions&&r.resolutions.length>0&&(s.resolutions=r.resolutions);try{return await t.put(a,s)}catch(t){throw t instanceof e.g&&t.status===409?new e.f(t.status,t.message,t.code):t instanceof e.g&&t.status===400?new e.p(t.status,t.message,t.code):t}}function readEnvironment(){return typeof process>`u`||!process.env?{}:{baseUrl:process.env.STANDARDS_API_URL||void 0,apiKey:process.env.STANDARDS_API_KEY||void 0}}function resolveConfig(t){if(globalThis.window!==void 0){if(t.apiKey)throw new e.h(`createStandards received an apiKey in a browser context. API keys belong to server code only (Route Handlers, Server Components, scripts).`);if(t.baseUrl===void 0)throw new e.h(`createStandards needs an explicit baseUrl in a browser context: STANDARDS_API_URL and STANDARDS_API_KEY are never read from the environment there.`);return{...t,baseUrl:t.baseUrl,apiKey:``}}let n=readEnvironment(),r=t.baseUrl??n.baseUrl;if(r===void 0)throw new e.h(`createStandards needs a base URL: pass baseUrl or set the STANDARDS_API_URL environment variable.`);let i=t.apiKey??n.apiKey;if(i===void 0)throw new e.h(`createStandards needs an API key: pass apiKey or set the STANDARDS_API_KEY environment variable.`);return{...t,baseUrl:r,apiKey:i}}function createStandards(t={}){let{schema:n,...r}=t;return buildStandards(e.n(resolveConfig(r)),n)}function buildStandards(e,t){let n={schema:{sync:(t,n)=>syncSchemaSource(e,t,n)},from:t=>createRecordsQuery(e,t),files:createFilesApi(e),documents:createDocumentsApi(e)};if(t!==void 0){let r=t.builders.map(e=>definitionOf(e).name);assertObjectNames(r),t.builders.forEach((t,i)=>{n[objectKeyOf(r[i])]=createRecordsQuery(e,t)})}return n}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return definitionOf}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return createFilesApi}}),Object.defineProperty(exports,"d",{enumerable:!0,get:function(){return hashSchemaSource}}),Object.defineProperty(exports,"f",{enumerable:!0,get:function(){return resolveSchemaSource}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return createRecordsQuery}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return createDocumentsApi}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return createStandards}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return reviveRecord}}),Object.defineProperty(exports,"p",{enumerable:!0,get:function(){return sourceIdFromPackageName}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return syncSchemaSource}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return serializeInput}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return buildStandards}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return defineSchemaSource}});
@@ -0,0 +1,2 @@
1
+ /*! © 2025-2026 AND YOU CREATE SAS (RCS Paris 940 190 614). Proprietary — see LICENSE (Standards SDK License 1.0). */
2
+ import{f as e,g as t,h as n,n as r,p as i}from"./http-transport-17TmxnFl.mjs";import{AggregateValidationError as a,DuplicateError as o,RecordQuery as s,SchemaErrorCode as c,ValidationError as l,assertSchemaSourceId as u,canonicalStringify as d,contentViewDefinitionSchema as f,parseSchemaGroupPresentation as p}from"@standards/schema";import{buildOperationPath as m,documentsOperations as h,filesOperations as g,recordAccessOperations as _,recordsOperations as v}from"@standards/schema/api";function objectKeyOf(e){return e.replace(/-([a-z0-9])/g,(e,t)=>t.toUpperCase())}const y=new Set([`from`,`files`,`documents`,`schema`]);function assertObjectKeys(e){let t=new Map;for(let r of e){if(r.includes(`--`)||r.endsWith(`-`))throw new n(`Object "${r}" has a doubled or trailing hyphen, which has no client key. Rename the object.`);let e=objectKeyOf(r);if(y.has(e))throw new n(`Object "${r}" maps to the client key "${e}", which is reserved. Rename the object.`);let i=t.get(e);if(i!==void 0&&i!==r)throw new n(`Objects "${i}" and "${r}" both map to the client key "${e}". Rename one of them.`);t.set(e,r)}}function buildView(e){let t=`build`in e&&typeof e.build==`function`?e.build():e,n=`kind`in t&&t.kind===`view`?t.definition:t,r=f.safeParse(n);if(r.success)return r.data;let i=typeof n==`object`&&n&&`name`in n?String(n.name):`(unnamed)`,a=l.fromZodErrors(r.error.issues.map(e=>({path:e.path.map(String),message:e.message})));throw new l(`View "${i}" is invalid. ${a.message}`,a.errors)}async function hashSchemaSource(e){let t=new TextEncoder().encode(d(e)),n=await crypto.subtle.digest(`SHA-256`,t);return Array.from(new Uint8Array(n),e=>e.toString(16).padStart(2,`0`)).join(``)}function assertObjectNames(e){let t=new Set;for(let n of e){if(t.has(n))throw new o(`object`,n);t.add(n)}assertObjectKeys(e)}function defineSchemaSource(e){return{id:e.id??null,builders:e.objects,views:e.views??[],label:e.label??null,icon:e.icon??null}}const b=new WeakMap;async function resolveOnce(e){e.id!==null&&u(e.id);let t=p({label:e.label??void 0,icon:e.icon??void 0}),n=e.builders.map(e=>e.build());assertObjectNames(n.map(e=>e.name));let r=e.views.map(buildView);return{id:e.id,hash:await hashSchemaSource({objects:n,views:r}),objects:n,views:r,label:t.label??null,icon:t.icon??null}}function resolveSchemaSource(e){let t=b.get(e);return t===void 0&&(t=resolveOnce(e),b.set(e,t)),t}function sourceIdFromPackageName(e){let t=e.toLowerCase().replace(/^@/,``).replace(/\//g,`-`);try{u(t)}catch{throw new n(`package.json name "${e}" is not a usable schema source id. Add id: "<lowercase-slug>" to defineSchemaSource.`)}return t}function assertTimeout(e){if(e!==void 0&&!(Number.isFinite(e)&&e>0))throw new l(`timeoutMs must be a positive number of milliseconds`,[{path:[`timeoutMs`],message:`Expected a positive, finite number`}])}function assertFileInput(e,t){if(!(e instanceof Blob))throw new l(`${t} must be a Blob or File`,[{path:[t],message:`Expected a Blob or File`}]);let n=e.name;if(typeof n!=`string`||n===``)throw new l(`${t} needs a filename`,[{path:[t,`name`],message:`Expected a non-empty filename`}]);if(e.type===``)throw new l(`${t} "${n}" needs a MIME type`,[{path:[t,`type`],message:`Expected a non-empty MIME type`}])}function reviveDocumentFile(e){return{...e,processedAt:e.processedAt===null?null:new Date(e.processedAt)}}function createDocumentsApi(e){async function attachToRecord(t){let{file:n}=t;assertFileInput(n,`file`),assertTimeout(t.timeoutMs);let r=m(v.attachDocument,{objectName:t.objectName,id:t.recordId}),i=new FormData;i.append(`files`,n,n.name),t.attributeName!==void 0&&i.append(`attributeName`,t.attributeName),t.documentId!==void 0&&i.append(`documentId`,t.documentId),t.title!==void 0&&i.append(`title`,t.title);let a=await e.postMultipart(r,i,{timeoutMs:t.timeoutMs});return{document:{id:a.document.id,title:a.document.title},file:reviveDocumentFile(a.file),action:a.action}}async function listFiles(t){return(await e.get(m(h.files,{id:t}))).map(reviveDocumentFile)}return{attachToRecord,listFiles}}function toUploadedFile(e){let t={id:e.id,name:e.name,mimeType:e.mimeType,size:e.size};return e.isPublic===!0&&typeof e.publicUrl==`string`?{...t,isPublic:!0,publicUrl:e.publicUrl}:{...t,isPublic:!1}}function createFilesApi(e){async function upload(t){assertFileInput(t.file,`file`),assertTimeout(t.timeoutMs);let[n]=await e.call(g.upload,{files:[t.file],public:t.public===!0?`true`:`false`,folderPath:t.folderPath},{timeoutMs:t.timeoutMs});return toUploadedFile(n)}async function getDownloadUrl(t){let{url:n}=await e.call(g.signedUrl,{id:t});return n}return{upload,getDownloadUrl}}const x=[`createdAt`,`updatedAt`,`deletedAt`];function dateAttributeNames(e){let t=new Set;for(let n of e?.attributes??[])n.type===`date`&&t.add(n.name);return t}function isRange(e){return typeof e==`object`&&!!e&&`start`in e&&`end`in e}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function flattenValues(e){let{values:t,...n}=e;return{...n,...isRecord(t)?t:{}}}function toDate(e){return typeof e==`string`?new Date(e):isRange(e)?{start:toDate(e.start),end:toDate(e.end)}:e}function reviveRecord(e,t){let n=dateAttributeNames(e),r=flattenValues(t);for(let e of x)e in r&&(r[e]=toDate(r[e]));for(let e of n)e in r&&(r[e]=toDate(r[e]));return r}function serializeInput(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,t instanceof Date?t.toISOString():t]))}var S=class RecordsQueryImpl extends s{constructor(e,t,n,r={object:t,combinator:`and`,rules:[],sorts:[]}){super(r),this.transport=e,this.objectName=t,this.definition=n}with(e){return new RecordsQueryImpl(this.transport,this.objectName,this.definition,{...this.state,...e})}body(){let e={};return this.state.search!==void 0&&(e.q=this.state.search),this.state.rules.length>0&&(e.filters={combinator:this.state.combinator,rules:this.state.rules}),this.state.sorts.length>0&&(e.sorts=this.state.sorts),this.state.limit!==void 0&&(e.limit=this.state.limit),this.state.offset!==void 0&&(e.offset=this.state.offset),e}revive(e){return reviveRecord(this.definition,e)}async export(e,t={}){if(!this.transport.postRaw)throw new n(`export() needs a transport with postRaw(path, body): Promise<Response>`);let{filters:r,sorts:i}=this.body(),{ids:a,locale:o,filename:s}=t;return await this.transport.postRaw(m(v.export,{objectName:this.objectName}),{q:this.state.search??``,...r?{filters:r}:{},...i?{sorts:i}:{},columns:e,...a?{ids:a}:{},...o?{locale:o}:{},timezone:t.timezone??Intl.DateTimeFormat().resolvedOptions().timeZone,...s?{filename:s}:{}})}async aggregate(e){if(this.state.search!==void 0)throw new a(c.AGGREGATE_SEARCH_UNSUPPORTED,`An aggregate cannot be narrowed by a search; use filters instead`);let t={...e,query:this.toDefinition(),timezone:e.timezone??Intl.DateTimeFormat().resolvedOptions().timeZone};return await this.transport.post(m(v.aggregate,{objectName:this.objectName}),t)}async fetchPage(){let e=this.state.search===void 0?`list`:`search`,t=await this.transport.post(m(v[e],{objectName:this.objectName}),this.body());return{records:t.data.map(e=>this.revive(e)),page:t.page}}async fetch(){let{records:e,page:t}=await this.fetchPage();return{records:e,total:t.total}}async all(){if(this.state.limit!==void 0&&this.state.limit<0)return(await this.fetch()).records;let e=this.state.limit??1/0,t=[],n=this.state.offset??0;for(;;){let r=Math.min(1e3,e-t.length);if(r<=0)return t;let{records:i,page:a}=await this.with({limit:r,offset:n}).fetchPage();if(t.push(...i),!a.hasMore)return t;let o=a.nextOffset??n+i.length;if(o<=n)return t;n=o}}async single(){let{records:e}=await this.limit(1).fetch();return e[0]??null}async get(e){let t=await this.transport.get(m(v.get,{objectName:this.objectName,id:e}));return this.revive(t)}async create(e){let t=await this.transport.post(m(v.create,{objectName:this.objectName}),{data:serializeInput(e)});return this.revive(t)}async update(e,t){let n=await this.transport.put(m(v.update,{objectName:this.objectName,id:e}),serializeInput(t));return this.revive(n)}async delete(e){await this.transport.delete(m(v.delete,{objectName:this.objectName,id:e}))}async inChunks(e,t){for(let n=0;n<e.length;n+=100)await t(e.slice(n,n+100),n)}async createMany(e){let t={created:[],errors:[]};return await this.inChunks(e,async(e,n)=>{let r=await this.transport.post(m(v.bulkCreate,{objectName:this.objectName}),{records:e.map(serializeInput)});t.created.push(...r.created.map(e=>this.revive(e))),t.errors.push(...r.errors.map(e=>({...e,index:e.index+n})))}),t}async updateMany(e){let t={updated:[],errors:[]};return await this.inChunks(e,async e=>{let n=await this.transport.post(m(v.bulkUpdate,{objectName:this.objectName}),{updates:e.map(({id:e,data:t})=>({id:e,data:serializeInput(t)}))});t.updated.push(...n.updated.map(e=>this.revive(e))),t.errors.push(...n.errors)}),t}async deleteMany(e){let t={deleted:[],errors:[]};return await this.inChunks(e,async e=>{let n=await this.transport.post(m(v.bulkDelete,{objectName:this.objectName}),{ids:e});t.deleted.push(...n.deleted),t.errors.push(...n.errors)}),t}async listAccess(e){return await this.transport.get(m(_.list,{objectName:this.objectName,recordId:e}))}async grantAccess(e,t,n){return await this.transport.put(m(_.grant,{objectName:this.objectName,recordId:e,actorId:t}),{role:n})}async revokeAccess(e,t){return await this.transport.delete(m(_.revoke,{objectName:this.objectName,recordId:e,actorId:t}))}async clearAccess(e){return await this.transport.delete(m(_.clear,{objectName:this.objectName,recordId:e}))}};const C=new WeakMap;function definitionOf(e){let t=C.get(e);if(t)return t;let n=e.build();return C.set(e,n),n}function createRecordsQuery(e,t){if(typeof t==`string`)return new S(e,t,null);let n=definitionOf(t);return new S(e,n.name,n)}async function syncSchemaSource(r,a,o={}){let s=await resolveSchemaSource(a);if(s.id===null)throw new n(`This schema source has no id. Add id: "<lowercase-slug>" to defineSchemaSource, or derive one with sourceIdFromPackageName(packageJson.name).`);let c=`/schema/sources/${encodeURIComponent(s.id)}`,l;try{l=await r.get(c)}catch(e){if(e instanceof t&&e.status===404)l=null;else throw e}if(l?.hash===s.hash&&(s.label===null||(l.label??null)===s.label)&&(s.icon===null||(l.icon??null)===s.icon))return{applied:!1,hash:s.hash};let u={hash:s.hash,objects:s.objects,views:s.views};s.label!==null&&(u.label=s.label),s.icon!==null&&(u.icon=s.icon),o.resolutions&&o.resolutions.length>0&&(u.resolutions=o.resolutions);try{return await r.put(c,u)}catch(n){throw n instanceof t&&n.status===409?new e(n.status,n.message,n.code):n instanceof t&&n.status===400?new i(n.status,n.message,n.code):n}}function readEnvironment(){return typeof process>`u`||!process.env?{}:{baseUrl:process.env.STANDARDS_API_URL||void 0,apiKey:process.env.STANDARDS_API_KEY||void 0}}function resolveConfig(e){if(globalThis.window!==void 0){if(e.apiKey)throw new n(`createStandards received an apiKey in a browser context. API keys belong to server code only (Route Handlers, Server Components, scripts).`);if(e.baseUrl===void 0)throw new n(`createStandards needs an explicit baseUrl in a browser context: STANDARDS_API_URL and STANDARDS_API_KEY are never read from the environment there.`);return{...e,baseUrl:e.baseUrl,apiKey:``}}let t=readEnvironment(),r=e.baseUrl??t.baseUrl;if(r===void 0)throw new n(`createStandards needs a base URL: pass baseUrl or set the STANDARDS_API_URL environment variable.`);let i=e.apiKey??t.apiKey;if(i===void 0)throw new n(`createStandards needs an API key: pass apiKey or set the STANDARDS_API_KEY environment variable.`);return{...e,baseUrl:r,apiKey:i}}function createStandards(e={}){let{schema:t,...n}=e;return buildStandards(r(resolveConfig(n)),t)}function buildStandards(e,t){let n={schema:{sync:(t,n)=>syncSchemaSource(e,t,n)},from:t=>createRecordsQuery(e,t),files:createFilesApi(e),documents:createDocumentsApi(e)};if(t!==void 0){let r=t.builders.map(e=>definitionOf(e).name);assertObjectNames(r),t.builders.forEach((t,i)=>{n[objectKeyOf(r[i])]=createRecordsQuery(e,t)})}return n}export{definitionOf as a,createFilesApi as c,hashSchemaSource as d,resolveSchemaSource as f,createRecordsQuery as i,createDocumentsApi as l,createStandards as n,reviveRecord as o,sourceIdFromPackageName as p,syncSchemaSource as r,serializeInput as s,buildStandards as t,defineSchemaSource as u};
@@ -0,0 +1,2 @@
1
+ /*! © 2025-2026 AND YOU CREATE SAS (RCS Paris 940 190 614). Proprietary — see LICENSE (Standards SDK License 1.0). */
2
+ import{SchemaErrorCode as e,ValidationError as t}from"@standards/schema";import{encodePathSegment as n,splitOperationInput as r}from"@standards/schema/api";var StandardsRequestError=class extends Error{constructor(e,t,n,r){super(t),this.name=`StandardsRequestError`,this.status=e,this.code=n,this.details=r}},StandardsAuthError=class extends StandardsRequestError{constructor(e,t,n,r){super(e,t,n,r),this.name=`StandardsAuthError`}},SchemaSourceConflictError=class extends StandardsRequestError{constructor(e,t,n){super(e,t,n),this.name=`SchemaSourceConflictError`;let r=/"([^"]+)" is owned by (\S+)/.exec(t);this.objectName=r?.[1]??``,this.owner=r?.[2]??``}},SchemaSourceValidationError=class extends StandardsRequestError{constructor(e,t,n){super(e,t,n),this.name=`SchemaSourceValidationError`}},StandardsConfigurationError=class extends Error{constructor(e){super(e),this.name=`StandardsConfigurationError`}};function schemaApiErrorCode(e){if(typeof e!=`object`||!e||!(`code`in e))return;let{code:t}=e;return typeof t==`string`?t:void 0}const i=new Set([e.CONFIGURATION_REQUIRED]);function isPermanentRefusal(e){let t=schemaApiErrorCode(e);return t!==void 0&&i.has(t)}function isObjectNotFound(t){if(typeof t!=`object`||!t)return!1;let{code:n,status:r}=t;return n===e.OBJECT_NOT_FOUND||r===404}function isDraftRevisionConflict(t){return schemaApiErrorCode(t)===e.DRAFT_REVISION_CONFLICT}function isViewNotFound(e){return typeof e!=`object`||!e?!1:e.status===404}function parseContentDispositionFilename(e){if(!e)return;let t=e.match(/filename\*\s*=\s*(?:UTF-8|utf-8)''([^;]+)/i);if(t?.[1])try{return decodeURIComponent(t[1].trim())}catch{}let n=e.match(/filename\s*=\s*"([^"]*)"|filename\s*=\s*([^;]+)/i);return(n?.[1]??n?.[2])?.trim()||void 0}function recordsPath(e,...t){return[`/records`,...[e,...t].map(n)].join(`/`)}function resolveWithinBase(e,n){let r=e.endsWith(`/`)?e:`${e}/`,i=new URL(r),a=n.replace(/^\/+/,``),[o]=a.split(/[?#]/);if((o??``).split(`/`).some(e=>e===`..`||e===`.`))throw new t(`Request path "${n}" walks outside its own collection`,[]);let s=new URL(a,i);if(s.origin!==i.origin||!s.pathname.startsWith(i.pathname))throw new t(`Request path "${n}" resolves outside the API base "${i.pathname}"`,[]);return s}function readJson(e){return e.status===204||e.headers.get(`content-length`)===`0`?null:e.json()}async function readDownload(e){let t=await e.blob();return{blob:t,filename:parseContentDispositionFilename(e.headers.get(`Content-Disposition`)),mimeType:e.headers.get(`Content-Type`)??t.type}}function multipartBody(e,t){let n=new FormData;for(let[r,i]of Object.entries(t??{}))if(i!=null){if(r===e)for(let t of Array.isArray(i)?i:[i]){let r=t.name;typeof r==`string`?n.append(e,t,r):n.append(e,t)}else n.append(r,String(i))}return n}function headerRecord(e){return e===void 0?{}:e instanceof Headers?Object.fromEntries(e.entries()):Array.isArray(e)?Object.fromEntries(e):{...e}}function withoutContentType(e){return Object.fromEntries(Object.entries(e).filter(([e])=>e.toLowerCase()!==`content-type`))}function parseJsonObject(e){try{let t=JSON.parse(e);return typeof t==`object`&&t?t:{}}catch{return}}function refusalFrom(e,t,n){let r=parseJsonObject(t),i=r?.message??r?.error??r?.detail,a=i==null?n&&r===void 0&&t?t:`Request failed with status ${e}`:String(i),o=typeof r?.code==`string`?r.code:void 0;return new(e===401||e===403?StandardsAuthError:StandardsRequestError)(e,a,o,r?.details)}function refusalOf(e,t){return refusalFrom(e,t,!1)}async function readRefusal(e){return refusalOf(e.status,await e.text().catch(()=>``))}function isTimeout(e){return e instanceof DOMException&&e.name===`TimeoutError`}function trimSlashes(e,t){let n=0,r=e.length;for(;t&&n<r&&e[n]===`/`;)n+=1;for(;r>n&&e[r-1]===`/`;)--r;return e.slice(n,r)}function backoff(e){return new Promise(t=>setTimeout(t,1e3*2**e))}function abortReason(e){return e?.aborted?e.reason:new DOMException(`The operation was aborted.`,`AbortError`)}function canReportUploadProgress(e){return typeof XMLHttpRequest>`u`?!1:e.fetch===void 0||e.uploadAuthorization!==void 0}function sendWithProgress(e,t){let{signal:n}=e;return n?.aborted?Promise.reject(abortReason(n)):new Promise((r,i)=>{let a=new XMLHttpRequest;a.open(e.method,e.url);for(let[t,n]of Object.entries(e.headers))a.setRequestHeader(t,n);let o=Object.keys(e.headers).some(e=>e.toLowerCase()===`authorization`);e.token&&!o&&a.setRequestHeader(`Authorization`,`Bearer ${e.token}`),a.upload.addEventListener(`progress`,t=>{t.lengthComputable&&e.onUploadProgress({loaded:t.loaded,total:t.total})});let onAbort=()=>a.abort();n?.addEventListener(`abort`,onAbort,{once:!0});let settle=()=>n?.removeEventListener(`abort`,onAbort);a.addEventListener(`load`,()=>{if(settle(),a.status<200||a.status>=300){i(refusalOf(a.status,a.responseText));return}try{r(t(a.responseText))}catch(e){i(e)}}),a.addEventListener(`error`,()=>{settle(),i(new StandardsRequestError(0,`Network request failed`))}),a.addEventListener(`abort`,()=>{settle(),i(abortReason(n))}),a.send(e.form)})}function createHttpTransport(e){let{baseUrl:t,onUnauthorized:n,getRetries:i=0}=e,a=e.timeoutMs??3e4,o=e.apiPrefix===void 0?void 0:trimSlashes(e.apiPrefix,!0),s=o?`${trimSlashes(t,!1)}/${o}`:t;function buildUrl(e,t){let n=resolveWithinBase(s,e);for(let[e,r]of Object.entries(t??{}))r!=null&&n.searchParams.set(e,String(r));return n.toString()}async function headersFor(t){let n={"Content-Type":`application/json`,...headerRecord(await e.headers?.()),...headerRecord(t.headers)};return t.body instanceof FormData?withoutContentType(n):n}function observe(t){try{e.onResponse?.(t)}catch{}}async function fetchOnce(t,n,r){let i=n.signal??void 0;i?.throwIfAborted();let a=r===null?void 0:AbortSignal.timeout(r),o=new AbortController,expire=()=>o.abort(a?.reason);a?.addEventListener(`abort`,expire,{once:!0});let s=i?AbortSignal.any([i,o.signal]):o.signal,c=new Promise((e,t)=>{s.addEventListener(`abort`,()=>t(s.reason),{once:!0})});try{let r=e.fetch??fetch,i=await headersFor(n);return await Promise.race([r(t,{...n,headers:i,signal:s}),c])}catch(e){throw i?.aborted?i.reason:e}finally{a?.removeEventListener(`abort`,expire)}}function connectionFailure(e){return e instanceof TypeError||isTimeout(e)?new StandardsRequestError(0,`Could not connect to ${t}`):e}async function refreshAndRetry(e,t,r){try{if(!await n?.())return;let i=await fetchOnce(e,t,r);return observe(i),i}catch{if(t.signal?.aborted)throw t.signal.reason;return}}async function readRefusalWithin(e){let t,n=new Promise(n=>{t=setTimeout(()=>n(refusalFrom(e.status,``,!1)),1500)});try{let t=e.text().catch(()=>``).then(t=>refusalFrom(e.status,t,!1));return await Promise.race([t,n])}finally{clearTimeout(t)}}async function send(e,t,r,o){let s=buildUrl(e,r.params),c=(t.method??`GET`).toUpperCase(),l=r.maxRetries??(c===`GET`?i:0),u=r.timeoutMs===void 0?a:r.timeoutMs;for(let e=0;;e++){let i=e<l,a;try{a=await fetchOnce(s,t,u)}catch(n){if(i&&n instanceof TypeError&&!t.signal?.aborted){await backoff(e);continue}throw connectionFailure(n)}if(observe(a),a.status>=500&&i){let t=await readRefusalWithin(a);if(isPermanentRefusal(t))throw t;await backoff(e);continue}if(a.status===401&&n&&(a=await refreshAndRetry(s,t,u)??a),!a.ok){let e=await a.text().catch(()=>``);throw refusalFrom(a.status,e,r.plainTextRefusal??!1)}return await o(a)}}async function stream(t,i,a={}){let{path:o,query:s,body:c,headers:l}=r(t,i??{}),u=buildUrl(o,s),{signal:d,onRequest:f}=a,p=e.fetch??fetch,attempt=async()=>(f?.(),await p(u,{method:t.method,body:c===void 0?void 0:JSON.stringify(c),signal:d,headers:await headersFor({headers:{...l,...a.headers}})})),m=await attempt();if(m.status===401){let e=await readRefusal(m);if(e.code===`MFA_REQUIRED`||!n||!await n().catch(()=>!1))throw e;d?.throwIfAborted(),m=await attempt()}if(!m.ok)throw await readRefusal(m);return m}async function json(e,t,n){return await send(t,{method:e,body:n?JSON.stringify(n):void 0},{},readJson)}return{async call(t,n,i={}){if(t.response===`events`)return await stream(t,n,{signal:i.signal});let{path:a,query:o,body:s,headers:c}=r(t,n??{});if(t.upload!==void 0&&i.onUploadProgress&&canReportUploadProgress(e)){i.signal?.throwIfAborted();let n=await e.uploadAuthorization?.()??null;return await sendWithProgress({url:buildUrl(a,o),method:t.method,headers:withoutContentType({...headerRecord(await e.headers?.()),...c}),token:n,form:multipartBody(t.upload.field,s),onUploadProgress:i.onUploadProgress,signal:i.signal},e=>e?JSON.parse(e):null)}let l=t.upload===void 0?s===void 0?void 0:JSON.stringify(s):multipartBody(t.upload.field,s),u=t.response===`bytes`?readDownload:readJson;return await send(a,{method:t.method,body:l,signal:i.signal,...c?{headers:c}:{},...i.keepalive?{keepalive:!0}:{}},{params:o,maxRetries:i.maxRetries,timeoutMs:i.timeoutMs},u)},stream,async get(e,t){return await send(e,{method:`GET`},{params:t},readJson)},post:(e,t)=>json(`POST`,e,t),patch:(e,t)=>json(`PATCH`,e,t),put:(e,t)=>json(`PUT`,e,t),delete:e=>json(`DELETE`,e),async getText(e,t){return await send(e,{method:`GET`},{params:t,plainTextRefusal:!0},e=>e.text())},async postRaw(e,t){return await send(e,{method:`POST`,body:JSON.stringify(t)},{plainTextRefusal:!0},e=>e)},async postMultipart(e,t,n={}){return await send(e,{method:`POST`,body:t},{timeoutMs:n.timeoutMs},readJson)}}}function createTransport(e){let{baseUrl:t,apiKey:n,tenantId:r,timeoutMs:i}=e,a={Authorization:`Bearer ${n}`,...r?{"X-Tenant-ID":r}:{}};return createHttpTransport({baseUrl:t,timeoutMs:i,headers:()=>a})}export{recordsPath as a,isObjectNotFound as c,schemaApiErrorCode as d,SchemaSourceConflictError as f,StandardsRequestError as g,StandardsConfigurationError as h,refusalOf as i,isPermanentRefusal as l,StandardsAuthError as m,createTransport as n,parseContentDispositionFilename as o,SchemaSourceValidationError as p,readRefusal as r,isDraftRevisionConflict as s,createHttpTransport as t,isViewNotFound as u};