@org-quicko/silo-client 1.0.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 (202) hide show
  1. package/README.md +313 -0
  2. package/dist/collections/collection-definition.d.cts +10 -0
  3. package/dist/collections/collection-definition.d.ts +10 -0
  4. package/dist/collections/collection-handle.d.cts +54 -0
  5. package/dist/collections/collection-handle.d.ts +54 -0
  6. package/dist/collections/collection-schema.d.cts +16 -0
  7. package/dist/collections/collection-schema.d.ts +16 -0
  8. package/dist/collections/collection-summary.d.cts +10 -0
  9. package/dist/collections/collection-summary.d.ts +10 -0
  10. package/dist/collections/collections.d.cts +19 -0
  11. package/dist/collections/collections.d.ts +19 -0
  12. package/dist/collections/json-schema.d.cts +9 -0
  13. package/dist/collections/json-schema.d.ts +9 -0
  14. package/dist/collections/reserved-field-names.d.cts +9 -0
  15. package/dist/collections/reserved-field-names.d.ts +9 -0
  16. package/dist/entries/entry-base.d.cts +31 -0
  17. package/dist/entries/entry-base.d.ts +31 -0
  18. package/dist/entries/entry-list-query.d.cts +11 -0
  19. package/dist/entries/entry-list-query.d.ts +11 -0
  20. package/dist/entries/entry-mapper.d.cts +13 -0
  21. package/dist/entries/entry-mapper.d.ts +13 -0
  22. package/dist/entries/entry-page-stream.d.cts +14 -0
  23. package/dist/entries/entry-page-stream.d.ts +14 -0
  24. package/dist/entries/entry-page.d.cts +16 -0
  25. package/dist/entries/entry-page.d.ts +16 -0
  26. package/dist/entries/entry-payload.d.cts +12 -0
  27. package/dist/entries/entry-payload.d.ts +12 -0
  28. package/dist/entries/entry-reader.d.cts +26 -0
  29. package/dist/entries/entry-reader.d.ts +26 -0
  30. package/dist/entries/entry-stream.d.cts +5 -0
  31. package/dist/entries/entry-stream.d.ts +5 -0
  32. package/dist/entries/entry.d.cts +25 -0
  33. package/dist/entries/entry.d.ts +25 -0
  34. package/dist/entries/resolved-entry.d.cts +11 -0
  35. package/dist/entries/resolved-entry.d.ts +11 -0
  36. package/dist/errors/conflict-error.d.cts +6 -0
  37. package/dist/errors/conflict-error.d.ts +6 -0
  38. package/dist/errors/error-code.d.cts +4 -0
  39. package/dist/errors/error-code.d.ts +4 -0
  40. package/dist/errors/error-factory.d.cts +15 -0
  41. package/dist/errors/error-factory.d.ts +15 -0
  42. package/dist/errors/error-payload.d.cts +13 -0
  43. package/dist/errors/error-payload.d.ts +13 -0
  44. package/dist/errors/forbidden-error.d.cts +5 -0
  45. package/dist/errors/forbidden-error.d.ts +5 -0
  46. package/dist/errors/internal-error.d.cts +6 -0
  47. package/dist/errors/internal-error.d.ts +6 -0
  48. package/dist/errors/invalid-response-error.d.cts +11 -0
  49. package/dist/errors/invalid-response-error.d.ts +11 -0
  50. package/dist/errors/media-delete-stalled-error.d.cts +14 -0
  51. package/dist/errors/media-delete-stalled-error.d.ts +14 -0
  52. package/dist/errors/media-in-use-error.d.cts +21 -0
  53. package/dist/errors/media-in-use-error.d.ts +21 -0
  54. package/dist/errors/network-error.d.cts +11 -0
  55. package/dist/errors/network-error.d.ts +11 -0
  56. package/dist/errors/not-found-error.d.cts +6 -0
  57. package/dist/errors/not-found-error.d.ts +6 -0
  58. package/dist/errors/request-aborted-error.d.cts +10 -0
  59. package/dist/errors/request-aborted-error.d.ts +10 -0
  60. package/dist/errors/silo-error.d.cts +12 -0
  61. package/dist/errors/silo-error.d.ts +12 -0
  62. package/dist/errors/timeout-error.d.cts +11 -0
  63. package/dist/errors/timeout-error.d.ts +11 -0
  64. package/dist/errors/unauthorized-error.d.cts +5 -0
  65. package/dist/errors/unauthorized-error.d.ts +5 -0
  66. package/dist/errors/validation-detail.d.cts +8 -0
  67. package/dist/errors/validation-detail.d.ts +8 -0
  68. package/dist/errors/validation-failed-error.d.cts +11 -0
  69. package/dist/errors/validation-failed-error.d.ts +11 -0
  70. package/dist/index.cjs +2095 -0
  71. package/dist/index.d.cts +96 -0
  72. package/dist/index.d.ts +96 -0
  73. package/dist/index.js +2053 -0
  74. package/dist/instance/health-report.d.cts +5 -0
  75. package/dist/instance/health-report.d.ts +5 -0
  76. package/dist/media/media-asset-mapper.d.cts +31 -0
  77. package/dist/media/media-asset-mapper.d.ts +31 -0
  78. package/dist/media/media-asset-payload.d.cts +20 -0
  79. package/dist/media/media-asset-payload.d.ts +20 -0
  80. package/dist/media/media-asset.d.cts +63 -0
  81. package/dist/media/media-asset.d.ts +63 -0
  82. package/dist/media/media-delete-failure.d.cts +16 -0
  83. package/dist/media/media-delete-failure.d.ts +16 -0
  84. package/dist/media/media-delete-options.d.cts +9 -0
  85. package/dist/media/media-delete-options.d.ts +9 -0
  86. package/dist/media/media-delete-report.d.cts +13 -0
  87. package/dist/media/media-delete-report.d.ts +13 -0
  88. package/dist/media/media-folder-delete.d.cts +10 -0
  89. package/dist/media/media-folder-delete.d.ts +10 -0
  90. package/dist/media/media-folder-move.d.cts +9 -0
  91. package/dist/media/media-folder-move.d.ts +9 -0
  92. package/dist/media/media-folders.d.cts +22 -0
  93. package/dist/media/media-folders.d.ts +22 -0
  94. package/dist/media/media-page-stream.d.cts +10 -0
  95. package/dist/media/media-page-stream.d.ts +10 -0
  96. package/dist/media/media-page.d.cts +19 -0
  97. package/dist/media/media-page.d.ts +19 -0
  98. package/dist/media/media-query.d.cts +24 -0
  99. package/dist/media/media-query.d.ts +24 -0
  100. package/dist/media/media-reference.d.cts +18 -0
  101. package/dist/media/media-reference.d.ts +18 -0
  102. package/dist/media/media-stream.d.cts +7 -0
  103. package/dist/media/media-stream.d.ts +7 -0
  104. package/dist/media/media-upload.d.cts +18 -0
  105. package/dist/media/media-upload.d.ts +18 -0
  106. package/dist/media/media-usage-page.d.cts +35 -0
  107. package/dist/media/media-usage-page.d.ts +35 -0
  108. package/dist/media/media-usage.d.cts +13 -0
  109. package/dist/media/media-usage.d.ts +13 -0
  110. package/dist/media/media.d.cts +37 -0
  111. package/dist/media/media.d.ts +37 -0
  112. package/dist/pagination/page-window.d.cts +14 -0
  113. package/dist/pagination/page-window.d.ts +14 -0
  114. package/dist/pagination/page.d.cts +27 -0
  115. package/dist/pagination/page.d.ts +27 -0
  116. package/dist/pagination/row-stream.d.cts +28 -0
  117. package/dist/pagination/row-stream.d.ts +28 -0
  118. package/dist/query/field-path.d.cts +14 -0
  119. package/dist/query/field-path.d.ts +14 -0
  120. package/dist/query/filter-expression.d.cts +15 -0
  121. package/dist/query/filter-expression.d.ts +15 -0
  122. package/dist/query/filter-field.d.cts +19 -0
  123. package/dist/query/filter-field.d.ts +19 -0
  124. package/dist/query/filter-node.d.cts +9 -0
  125. package/dist/query/filter-node.d.ts +9 -0
  126. package/dist/query/filter-operator.d.cts +7 -0
  127. package/dist/query/filter-operator.d.ts +7 -0
  128. package/dist/query/filter.d.cts +18 -0
  129. package/dist/query/filter.d.ts +18 -0
  130. package/dist/query/sort-term.d.cts +13 -0
  131. package/dist/query/sort-term.d.ts +13 -0
  132. package/dist/query/sort.d.cts +15 -0
  133. package/dist/query/sort.d.ts +15 -0
  134. package/dist/query/typed-filter.d.cts +32 -0
  135. package/dist/query/typed-filter.d.ts +32 -0
  136. package/dist/request-options.d.cts +9 -0
  137. package/dist/request-options.d.ts +9 -0
  138. package/dist/scope/delete-options.d.cts +9 -0
  139. package/dist/scope/delete-options.d.ts +9 -0
  140. package/dist/scope/environment-handle.d.cts +29 -0
  141. package/dist/scope/environment-handle.d.ts +29 -0
  142. package/dist/scope/environment.d.cts +8 -0
  143. package/dist/scope/environment.d.ts +8 -0
  144. package/dist/scope/environments.d.cts +11 -0
  145. package/dist/scope/environments.d.ts +11 -0
  146. package/dist/scope/project-handle.d.cts +22 -0
  147. package/dist/scope/project-handle.d.ts +22 -0
  148. package/dist/scope/project.d.cts +8 -0
  149. package/dist/scope/project.d.ts +8 -0
  150. package/dist/scope/projects.d.cts +10 -0
  151. package/dist/scope/projects.d.ts +10 -0
  152. package/dist/scope/rename-options.d.cts +10 -0
  153. package/dist/scope/rename-options.d.ts +10 -0
  154. package/dist/scope/rename-report.d.cts +21 -0
  155. package/dist/scope/rename-report.d.ts +21 -0
  156. package/dist/scope/scope-reference.d.cts +12 -0
  157. package/dist/scope/scope-reference.d.ts +12 -0
  158. package/dist/search/search-engine.d.cts +3 -0
  159. package/dist/search/search-engine.d.ts +3 -0
  160. package/dist/search/search-hit.d.cts +18 -0
  161. package/dist/search/search-hit.d.ts +18 -0
  162. package/dist/search/search-page.d.cts +19 -0
  163. package/dist/search/search-page.d.ts +19 -0
  164. package/dist/search/search-query.d.cts +11 -0
  165. package/dist/search/search-query.d.ts +11 -0
  166. package/dist/search/search-reach.d.cts +12 -0
  167. package/dist/search/search-reach.d.ts +12 -0
  168. package/dist/search/search-snippet.d.cts +8 -0
  169. package/dist/search/search-snippet.d.ts +8 -0
  170. package/dist/search/search.d.cts +18 -0
  171. package/dist/search/search.d.ts +18 -0
  172. package/dist/silo-options.d.cts +12 -0
  173. package/dist/silo-options.d.ts +12 -0
  174. package/dist/silo.d.cts +42 -0
  175. package/dist/silo.d.ts +42 -0
  176. package/dist/transport/abort-signals.d.cts +23 -0
  177. package/dist/transport/abort-signals.d.ts +23 -0
  178. package/dist/transport/api-path.d.cts +36 -0
  179. package/dist/transport/api-path.d.ts +36 -0
  180. package/dist/transport/fetch-function.d.cts +11 -0
  181. package/dist/transport/fetch-function.d.ts +11 -0
  182. package/dist/transport/page-payload.d.cts +15 -0
  183. package/dist/transport/page-payload.d.ts +15 -0
  184. package/dist/transport/query-string.d.cts +10 -0
  185. package/dist/transport/query-string.d.ts +10 -0
  186. package/dist/transport/response-decoder.d.cts +14 -0
  187. package/dist/transport/response-decoder.d.ts +14 -0
  188. package/dist/transport/route-inventory.d.cts +22 -0
  189. package/dist/transport/route-inventory.d.ts +22 -0
  190. package/dist/transport/transport-request.d.cts +18 -0
  191. package/dist/transport/transport-request.d.ts +18 -0
  192. package/dist/transport/transport.d.cts +45 -0
  193. package/dist/transport/transport.d.ts +45 -0
  194. package/dist/variables/environment-variables.d.cts +14 -0
  195. package/dist/variables/environment-variables.d.ts +14 -0
  196. package/dist/variables/project-variables.d.cts +38 -0
  197. package/dist/variables/project-variables.d.ts +38 -0
  198. package/dist/variables/variable-declaration.d.cts +10 -0
  199. package/dist/variables/variable-declaration.d.ts +10 -0
  200. package/dist/variables/variable.d.cts +17 -0
  201. package/dist/variables/variable.d.ts +17 -0
  202. package/package.json +58 -0
package/dist/index.js ADDED
@@ -0,0 +1,2053 @@
1
+ // src/pagination/page-window.ts
2
+ class PageWindow {
3
+ limit;
4
+ offset;
5
+ constructor(limit, offset) {
6
+ this.limit = limit;
7
+ this.offset = offset;
8
+ }
9
+ next() {
10
+ return new PageWindow(this.limit, this.offset + this.limit);
11
+ }
12
+ previous() {
13
+ if (this.offset <= 0)
14
+ return null;
15
+ return new PageWindow(this.limit, Math.max(0, this.offset - this.limit));
16
+ }
17
+ }
18
+
19
+ // src/transport/api-path.ts
20
+ class ApiPath {
21
+ static health() {
22
+ return "/api/health";
23
+ }
24
+ static projects() {
25
+ return "/api/projects";
26
+ }
27
+ static project(project) {
28
+ return `/api/projects/${encodeURIComponent(project)}`;
29
+ }
30
+ static environments(project) {
31
+ return `${ApiPath.project(project)}/envs`;
32
+ }
33
+ static environment(project, env) {
34
+ return `${ApiPath.environments(project)}/${encodeURIComponent(env)}`;
35
+ }
36
+ static projectVariables(project) {
37
+ return `${ApiPath.project(project)}/variables`;
38
+ }
39
+ static projectVariable(project, name) {
40
+ return `${ApiPath.projectVariables(project)}/${encodeURIComponent(name)}`;
41
+ }
42
+ static environmentVariables(project, env) {
43
+ return `${ApiPath.environment(project, env)}/variables`;
44
+ }
45
+ static environmentVariable(project, env, name) {
46
+ return `${ApiPath.environmentVariables(project, env)}/${encodeURIComponent(name)}`;
47
+ }
48
+ static collections(project, env) {
49
+ return `${ApiPath.environment(project, env)}/collections`;
50
+ }
51
+ static collection(project, env, name) {
52
+ return `${ApiPath.collections(project, env)}/${encodeURIComponent(name)}`;
53
+ }
54
+ static schemas(project, env) {
55
+ return `${ApiPath.environment(project, env)}/schemas`;
56
+ }
57
+ static collectionSchema(project, env, name) {
58
+ return `${ApiPath.collection(project, env, name)}/schema`;
59
+ }
60
+ static entries(project, env, name) {
61
+ return ApiPath.collection(project, env, name);
62
+ }
63
+ static entry(project, env, name, id) {
64
+ return `${ApiPath.collection(project, env, name)}/${encodeURIComponent(id)}`;
65
+ }
66
+ static collectionSearch(project, env, name) {
67
+ return `${ApiPath.collection(project, env, name)}/search`;
68
+ }
69
+ static environmentSearch(project, env) {
70
+ return `${ApiPath.environment(project, env)}/search`;
71
+ }
72
+ static instanceSearch() {
73
+ return "/api/search";
74
+ }
75
+ static media() {
76
+ return "/api/media";
77
+ }
78
+ static mediaExtensions() {
79
+ return "/api/media/extensions";
80
+ }
81
+ static mediaAsset(id) {
82
+ return `/api/media/${encodeURIComponent(id)}`;
83
+ }
84
+ static mediaAssetUsages(id) {
85
+ return `${ApiPath.mediaAsset(id)}/usages`;
86
+ }
87
+ static mediaBulkDelete() {
88
+ return "/api/media/delete";
89
+ }
90
+ static mediaFolders() {
91
+ return "/api/media/folders";
92
+ }
93
+ }
94
+
95
+ // src/media/media-asset-mapper.ts
96
+ class MediaAssetMapper {
97
+ static toRecord(payload) {
98
+ return {
99
+ id: payload.id,
100
+ filename: payload.filename,
101
+ folder: payload.folder,
102
+ blobKey: payload.blob_key,
103
+ sizeInBytes: payload.size,
104
+ contentType: payload.content_type,
105
+ hash: payload.hash,
106
+ state: payload.state,
107
+ tags: payload.tags,
108
+ url: payload.url,
109
+ usageCount: payload.usage_count ?? 0,
110
+ createdAt: new Date(payload.created_at),
111
+ updatedAt: new Date(payload.updated_at)
112
+ };
113
+ }
114
+ static toUsage(payload) {
115
+ return {
116
+ mediaId: typeof payload.media_id === "string" ? payload.media_id : "",
117
+ project: typeof payload.project === "string" ? payload.project : "",
118
+ environment: typeof payload.env === "string" ? payload.env : "",
119
+ collection: typeof payload.collection === "string" ? payload.collection : "",
120
+ entryId: typeof payload.entry_id === "string" ? payload.entry_id : ""
121
+ };
122
+ }
123
+ static toUsagePage(body) {
124
+ return {
125
+ items: body.items.map((item) => MediaAssetMapper.toUsage(item)),
126
+ total: body.total,
127
+ visible: body.visible,
128
+ visibleCapped: body.visible_capped
129
+ };
130
+ }
131
+ }
132
+
133
+ // src/media/media-reference.ts
134
+ class MediaReference {
135
+ static Scheme = "silo://media/";
136
+ static of(id) {
137
+ return MediaReference.Scheme + id;
138
+ }
139
+ static idOf(value) {
140
+ if (typeof value !== "string" || !value.startsWith(MediaReference.Scheme))
141
+ return null;
142
+ const id = value.slice(MediaReference.Scheme.length).split(/[#?/]/)[0];
143
+ return id ? id : null;
144
+ }
145
+ }
146
+
147
+ // src/pagination/page.ts
148
+ class Page {
149
+ rows;
150
+ window;
151
+ total;
152
+ truncated;
153
+ constructor(rows, total, window, truncated = false) {
154
+ this.rows = rows;
155
+ this.total = total;
156
+ this.window = window;
157
+ this.truncated = truncated;
158
+ }
159
+ get limit() {
160
+ return this.window.limit;
161
+ }
162
+ get offset() {
163
+ return this.window.offset;
164
+ }
165
+ get pageNumber() {
166
+ return Math.floor(this.offset / this.limit) + 1;
167
+ }
168
+ get pageCount() {
169
+ if (this.truncated)
170
+ return null;
171
+ return Math.max(1, Math.ceil(this.total / this.limit));
172
+ }
173
+ get hasMore() {
174
+ if (this.truncated)
175
+ return this.rows.length === this.limit;
176
+ return this.offset + this.rows.length < this.total;
177
+ }
178
+ windowForNext() {
179
+ return this.hasMore ? this.window.next() : null;
180
+ }
181
+ [Symbol.iterator]() {
182
+ return this.rows[Symbol.iterator]();
183
+ }
184
+ }
185
+
186
+ // src/media/media-usage-page.ts
187
+ var DefaultUsageLimit = 50;
188
+
189
+ class MediaUsagePage extends Page {
190
+ transport;
191
+ assetId;
192
+ visible;
193
+ visibleCapped;
194
+ constructor(rows, total, visible, visibleCapped, window, transport, assetId) {
195
+ super(rows, total, window);
196
+ this.transport = transport;
197
+ this.assetId = assetId;
198
+ this.visible = visible;
199
+ this.visibleCapped = visibleCapped;
200
+ }
201
+ get usages() {
202
+ return this.rows;
203
+ }
204
+ get pageCount() {
205
+ return Math.max(1, Math.ceil(this.visible / this.limit));
206
+ }
207
+ get hasMore() {
208
+ return this.offset + this.rows.length < this.visible;
209
+ }
210
+ async next(options) {
211
+ const window = this.windowForNext();
212
+ return window ? MediaUsagePage.loadWindow(this.transport, this.assetId, window, options) : null;
213
+ }
214
+ async previous(options) {
215
+ const window = this.window.previous();
216
+ return window ? MediaUsagePage.loadWindow(this.transport, this.assetId, window, options) : null;
217
+ }
218
+ static load(transport, assetId, query, options) {
219
+ const window = new PageWindow(query.limit ?? DefaultUsageLimit, query.offset ?? 0);
220
+ return MediaUsagePage.loadWindow(transport, assetId, window, options);
221
+ }
222
+ static async loadWindow(transport, assetId, window, options) {
223
+ const body = await transport.json({
224
+ method: "GET",
225
+ path: ApiPath.mediaAssetUsages(assetId),
226
+ query: { limit: window.limit, offset: window.offset },
227
+ signal: options?.signal,
228
+ timeoutMilliseconds: options?.timeoutMilliseconds
229
+ });
230
+ const mapped = MediaAssetMapper.toUsagePage(body);
231
+ return new MediaUsagePage(mapped.items, mapped.total, mapped.visible, mapped.visibleCapped, window, transport, assetId);
232
+ }
233
+ }
234
+
235
+ // src/media/media-asset.ts
236
+ class MediaAsset {
237
+ transport;
238
+ record;
239
+ constructor(transport, record) {
240
+ this.transport = transport;
241
+ this.record = record;
242
+ }
243
+ get id() {
244
+ return this.record.id;
245
+ }
246
+ get filename() {
247
+ return this.record.filename;
248
+ }
249
+ get folder() {
250
+ return this.record.folder;
251
+ }
252
+ get sizeInBytes() {
253
+ return this.record.sizeInBytes;
254
+ }
255
+ get contentType() {
256
+ return this.record.contentType;
257
+ }
258
+ get hash() {
259
+ return this.record.hash;
260
+ }
261
+ get state() {
262
+ return this.record.state;
263
+ }
264
+ get tags() {
265
+ return this.record.tags;
266
+ }
267
+ get url() {
268
+ return this.record.url;
269
+ }
270
+ get usageCount() {
271
+ return this.record.usageCount;
272
+ }
273
+ get createdAt() {
274
+ return this.record.createdAt;
275
+ }
276
+ get updatedAt() {
277
+ return this.record.updatedAt;
278
+ }
279
+ get blobKey() {
280
+ return this.record.blobKey;
281
+ }
282
+ get reference() {
283
+ return MediaReference.of(this.id);
284
+ }
285
+ async rename(filename, options) {
286
+ return this.patch({ filename }, options);
287
+ }
288
+ async moveTo(folder, options) {
289
+ return this.patch({ folder }, options);
290
+ }
291
+ async setTags(tags, options) {
292
+ return this.patch({ tags: [...tags] }, options);
293
+ }
294
+ async delete(options) {
295
+ await this.transport.empty({
296
+ method: "DELETE",
297
+ path: ApiPath.mediaAsset(this.id),
298
+ query: options?.force ? { force: true } : undefined,
299
+ signal: options?.signal,
300
+ timeoutMilliseconds: options?.timeoutMilliseconds
301
+ });
302
+ }
303
+ usages(query = {}, options) {
304
+ return MediaUsagePage.load(this.transport, this.id, query, options);
305
+ }
306
+ async refresh(options) {
307
+ const payload = await this.transport.json({
308
+ method: "GET",
309
+ path: ApiPath.mediaAsset(this.id),
310
+ signal: options?.signal,
311
+ timeoutMilliseconds: options?.timeoutMilliseconds
312
+ });
313
+ this.record = MediaAssetMapper.toRecord(payload);
314
+ return this;
315
+ }
316
+ toJSON() {
317
+ return { ...this.record };
318
+ }
319
+ async patch(body, options) {
320
+ const payload = await this.transport.json({
321
+ method: "PATCH",
322
+ path: ApiPath.mediaAsset(this.id),
323
+ body,
324
+ signal: options?.signal,
325
+ timeoutMilliseconds: options?.timeoutMilliseconds
326
+ });
327
+ this.record = MediaAssetMapper.toRecord(payload);
328
+ return this;
329
+ }
330
+ }
331
+
332
+ // src/media/media-delete-report.ts
333
+ class MediaDeleteReport {
334
+ deleted;
335
+ failed;
336
+ constructor(deleted, failed) {
337
+ this.deleted = deleted;
338
+ this.failed = failed;
339
+ }
340
+ static fromWireBody(body) {
341
+ return new MediaDeleteReport(body.deleted, body.failed.map(MediaDeleteReport.toFailure));
342
+ }
343
+ static toFailure(entry) {
344
+ const failure = {
345
+ id: String(entry.id),
346
+ code: String(entry.code),
347
+ message: String(entry.message)
348
+ };
349
+ if (typeof entry.usage_count === "number")
350
+ failure.usageCount = entry.usage_count;
351
+ if (typeof entry.visible_count === "number")
352
+ failure.visibleCount = entry.visible_count;
353
+ if (typeof entry.visible_capped === "boolean")
354
+ failure.visibleCapped = entry.visible_capped;
355
+ if (Array.isArray(entry.referrers)) {
356
+ failure.referrers = entry.referrers.map((usage) => MediaAssetMapper.toUsage(usage));
357
+ }
358
+ return failure;
359
+ }
360
+ }
361
+
362
+ // src/media/media-folders.ts
363
+ class MediaFolders {
364
+ transport;
365
+ constructor(transport) {
366
+ this.transport = transport;
367
+ }
368
+ async list(options) {
369
+ const body = await this.transport.json({
370
+ method: "GET",
371
+ path: ApiPath.mediaFolders(),
372
+ signal: options?.signal,
373
+ timeoutMilliseconds: options?.timeoutMilliseconds
374
+ });
375
+ return body.items;
376
+ }
377
+ async create(path, options) {
378
+ const body = await this.transport.json({
379
+ method: "POST",
380
+ path: ApiPath.mediaFolders(),
381
+ body: { path },
382
+ signal: options?.signal,
383
+ timeoutMilliseconds: options?.timeoutMilliseconds
384
+ });
385
+ return body.path;
386
+ }
387
+ rename(from, to, options) {
388
+ return this.transport.json({
389
+ method: "PATCH",
390
+ path: ApiPath.mediaFolders(),
391
+ body: { from, to, merge: options?.merge === true },
392
+ signal: options?.signal,
393
+ timeoutMilliseconds: options?.timeoutMilliseconds
394
+ });
395
+ }
396
+ async delete(path, options) {
397
+ await this.transport.empty({
398
+ method: "DELETE",
399
+ path: ApiPath.mediaFolders(),
400
+ query: {
401
+ path,
402
+ ...options?.recursive ? { recursive: true } : {},
403
+ ...options?.force ? { force: true } : {}
404
+ },
405
+ signal: options?.signal,
406
+ timeoutMilliseconds: options?.timeoutMilliseconds
407
+ });
408
+ }
409
+ }
410
+
411
+ // src/media/media-page.ts
412
+ class MediaPage extends Page {
413
+ transport;
414
+ wireQuery;
415
+ constructor(rows, total, window, transport, wireQuery) {
416
+ super(rows, total, window);
417
+ this.transport = transport;
418
+ this.wireQuery = wireQuery;
419
+ }
420
+ get files() {
421
+ return this.rows;
422
+ }
423
+ async next(options) {
424
+ const window = this.windowForNext();
425
+ return window ? MediaPage.loadWindow(this.transport, this.wireQuery, window, options) : null;
426
+ }
427
+ async previous(options) {
428
+ const window = this.window.previous();
429
+ return window ? MediaPage.loadWindow(this.transport, this.wireQuery, window, options) : null;
430
+ }
431
+ static async loadWindow(transport, wireQuery, window, options) {
432
+ const body = await transport.json({
433
+ method: "GET",
434
+ path: ApiPath.media(),
435
+ query: { ...wireQuery, limit: window.limit, offset: window.offset },
436
+ signal: options?.signal,
437
+ timeoutMilliseconds: options?.timeoutMilliseconds
438
+ });
439
+ const rows = body.items.map((payload) => new MediaAsset(transport, MediaAssetMapper.toRecord(payload)));
440
+ return new MediaPage(rows, body.total, new PageWindow(body.limit, body.offset), transport, wireQuery);
441
+ }
442
+ }
443
+
444
+ // src/errors/request-aborted-error.ts
445
+ class RequestAbortedError extends Error {
446
+ method;
447
+ path;
448
+ constructor(method, path) {
449
+ super(`${method} ${path} was aborted by the caller`);
450
+ this.name = "RequestAbortedError";
451
+ this.method = method;
452
+ this.path = path;
453
+ Object.setPrototypeOf(this, RequestAbortedError.prototype);
454
+ }
455
+ }
456
+
457
+ // src/media/media-page-stream.ts
458
+ class MediaPageStream {
459
+ first;
460
+ options;
461
+ constructor(first, options = {}) {
462
+ this.first = first;
463
+ this.options = options;
464
+ }
465
+ async* [Symbol.asyncIterator]() {
466
+ let page = await this.first();
467
+ while (page) {
468
+ if (this.options.signal?.aborted) {
469
+ throw new RequestAbortedError("GET", "stream");
470
+ }
471
+ yield page;
472
+ page = page.hasMore ? await page.next(this.options) : null;
473
+ }
474
+ }
475
+ }
476
+
477
+ // src/pagination/row-stream.ts
478
+ class RowStream {
479
+ loader;
480
+ startingLimit;
481
+ options;
482
+ constructor(loader, startingLimit, options = {}) {
483
+ this.loader = loader;
484
+ this.startingLimit = startingLimit;
485
+ this.options = options;
486
+ }
487
+ async* [Symbol.asyncIterator]() {
488
+ let window = new PageWindow(this.startingLimit, 0);
489
+ while (window) {
490
+ if (this.options.signal?.aborted) {
491
+ throw new RequestAbortedError("GET", "stream");
492
+ }
493
+ const page = await this.loader(window);
494
+ yield* page.rows;
495
+ const short = page.rows.length === 0 || page.rows.length < page.window.limit;
496
+ window = short ? null : page.window.next();
497
+ }
498
+ }
499
+ async toArray() {
500
+ const rows = [];
501
+ for await (const row of this)
502
+ rows.push(row);
503
+ return rows;
504
+ }
505
+ }
506
+
507
+ // src/media/media-stream.ts
508
+ class MediaStream extends RowStream {
509
+ }
510
+
511
+ // src/media/media.ts
512
+ var BulkDeleteCap = 100;
513
+
514
+ class Media {
515
+ transport;
516
+ folders;
517
+ constructor(transport) {
518
+ this.transport = transport;
519
+ this.folders = new MediaFolders(transport);
520
+ }
521
+ async upload(input, second, third) {
522
+ const form = new FormData;
523
+ let folder;
524
+ let options;
525
+ if (input instanceof Blob) {
526
+ const fileOptions = second ?? {};
527
+ form.set("file", input, Media.filenameOf(input, fileOptions.filename));
528
+ folder = fileOptions.folder;
529
+ options = third ?? fileOptions;
530
+ } else {
531
+ form.set("file", Media.toBlob(input.bytes, input.contentType), input.filename);
532
+ folder = input.folder;
533
+ options = second;
534
+ }
535
+ if (folder)
536
+ form.set("folder", folder);
537
+ const payload = await this.transport.upload({ method: "POST", path: ApiPath.media(), signal: options?.signal, timeoutMilliseconds: options?.timeoutMilliseconds }, form);
538
+ return new MediaAsset(this.transport, MediaAssetMapper.toRecord(payload));
539
+ }
540
+ list(query = {}, options) {
541
+ const window = new PageWindow(query.limit ?? 50, query.offset ?? 0);
542
+ return MediaPage.loadWindow(this.transport, Media.toWireQuery(query), window, options);
543
+ }
544
+ all(query = {}, options) {
545
+ const wireQuery = Media.toWireQuery(query);
546
+ const loader = async (window) => {
547
+ const page = await MediaPage.loadWindow(this.transport, wireQuery, window, options);
548
+ return { rows: [...page], window: new PageWindow(page.limit, page.offset) };
549
+ };
550
+ return new MediaStream(loader, query.limit ?? 50, options);
551
+ }
552
+ pages(query = {}, options) {
553
+ return new MediaPageStream(() => this.list(query, options), options);
554
+ }
555
+ async get(id, options) {
556
+ const payload = await this.transport.json({
557
+ method: "GET",
558
+ path: ApiPath.mediaAsset(id),
559
+ signal: options?.signal,
560
+ timeoutMilliseconds: options?.timeoutMilliseconds
561
+ });
562
+ return new MediaAsset(this.transport, MediaAssetMapper.toRecord(payload));
563
+ }
564
+ async extensions(options) {
565
+ const body = await this.transport.json({
566
+ method: "GET",
567
+ path: ApiPath.mediaExtensions(),
568
+ signal: options?.signal,
569
+ timeoutMilliseconds: options?.timeoutMilliseconds
570
+ });
571
+ return body.items;
572
+ }
573
+ async deleteMany(ids, options) {
574
+ if (ids.length > BulkDeleteCap) {
575
+ throw new Error(`deleteMany accepts at most ${BulkDeleteCap} ids per request, got ${ids.length}`);
576
+ }
577
+ const body = await this.transport.json({
578
+ method: "POST",
579
+ path: ApiPath.mediaBulkDelete(),
580
+ body: { ids: [...ids], force: options?.force === true },
581
+ signal: options?.signal,
582
+ timeoutMilliseconds: options?.timeoutMilliseconds
583
+ });
584
+ return MediaDeleteReport.fromWireBody(body);
585
+ }
586
+ static toWireQuery(query) {
587
+ return {
588
+ q: query.text,
589
+ folder: query.folder,
590
+ recursive: query.recursive,
591
+ type: query.type,
592
+ ext: query.extension,
593
+ tag: query.tag,
594
+ modified_after: query.modifiedAfter,
595
+ modified_before: query.modifiedBefore,
596
+ sort: query.sort
597
+ };
598
+ }
599
+ static toBlob(bytes, contentType) {
600
+ if (bytes instanceof Blob)
601
+ return bytes;
602
+ return new Blob([bytes], contentType ? { type: contentType } : undefined);
603
+ }
604
+ static filenameOf(input, explicit) {
605
+ if (explicit)
606
+ return explicit;
607
+ if (input instanceof File && input.name)
608
+ return input.name;
609
+ throw new Error("media upload: a Blob has no filename — pass { filename } explicitly");
610
+ }
611
+ }
612
+
613
+ // src/variables/variable.ts
614
+ class Variable {
615
+ name;
616
+ description;
617
+ value;
618
+ setIn;
619
+ createdAt;
620
+ updatedAt;
621
+ constructor(name, description, value, setIn, createdAt, updatedAt) {
622
+ this.name = name;
623
+ this.description = description;
624
+ this.value = value;
625
+ this.setIn = setIn;
626
+ this.createdAt = createdAt;
627
+ this.updatedAt = updatedAt;
628
+ }
629
+ static fromWire(payload) {
630
+ return new Variable(payload.name, payload.description, payload.value, payload.set_in, new Date(payload.created_at), new Date(payload.updated_at));
631
+ }
632
+ }
633
+
634
+ // src/variables/project-variables.ts
635
+ class ProjectVariables {
636
+ transport;
637
+ project;
638
+ constructor(transport, project) {
639
+ this.transport = transport;
640
+ this.project = project;
641
+ }
642
+ async declare(name, options = {}) {
643
+ const payload = await this.transport.json({
644
+ method: "POST",
645
+ path: ApiPath.projectVariables(this.project),
646
+ query: { env: options.environment },
647
+ body: { name, description: options.description, value: options.value },
648
+ signal: options.signal,
649
+ timeoutMilliseconds: options.timeoutMilliseconds
650
+ });
651
+ return Variable.fromWire(payload);
652
+ }
653
+ async rename(name, to, options = {}) {
654
+ return this.updateDeclaration(name, { name: to }, options);
655
+ }
656
+ async describe(name, description, options = {}) {
657
+ return this.updateDeclaration(name, { description }, options);
658
+ }
659
+ async undeclare(name, options = {}) {
660
+ await this.transport.empty({
661
+ method: "DELETE",
662
+ path: ApiPath.projectVariable(this.project, name),
663
+ query: { env: options.environment },
664
+ signal: options.signal,
665
+ timeoutMilliseconds: options.timeoutMilliseconds
666
+ });
667
+ }
668
+ async updateDeclaration(name, body, options) {
669
+ const payload = await this.transport.json({
670
+ method: "PATCH",
671
+ path: ApiPath.projectVariable(this.project, name),
672
+ query: { env: options.environment },
673
+ body,
674
+ signal: options.signal,
675
+ timeoutMilliseconds: options.timeoutMilliseconds
676
+ });
677
+ return Variable.fromWire(payload);
678
+ }
679
+ }
680
+
681
+ // src/entries/entry-mapper.ts
682
+ class EntryMapper {
683
+ static fieldsOf(payload) {
684
+ const { id: _id, rev: _rev, created_at: _createdAt, updated_at: _updatedAt, ...fields } = payload;
685
+ return fields;
686
+ }
687
+ static toPayload(id, rev, fields, createdAt, updatedAt) {
688
+ return {
689
+ id,
690
+ rev,
691
+ ...fields,
692
+ created_at: createdAt.toISOString(),
693
+ updated_at: updatedAt.toISOString()
694
+ };
695
+ }
696
+ }
697
+
698
+ // src/entries/entry-base.ts
699
+ class EntryBase {
700
+ context;
701
+ id;
702
+ rev;
703
+ createdAt;
704
+ updatedAt;
705
+ fields;
706
+ constructor(context, payload) {
707
+ this.context = context;
708
+ this.id = String(payload.id);
709
+ this.rev = Number(payload.rev);
710
+ this.createdAt = new Date(payload.created_at);
711
+ this.updatedAt = new Date(payload.updated_at);
712
+ this.fields = EntryMapper.fieldsOf(payload);
713
+ }
714
+ toJSON() {
715
+ return EntryMapper.toPayload(this.id, this.rev, this.fields, this.createdAt, this.updatedAt);
716
+ }
717
+ async delete(options = {}) {
718
+ await this.context.transport.empty({
719
+ method: "DELETE",
720
+ path: ApiPath.entry(this.context.project, this.context.environment, this.context.collection, this.id),
721
+ query: { rev: this.rev },
722
+ ...options
723
+ });
724
+ }
725
+ }
726
+
727
+ // src/entries/resolved-entry.ts
728
+ class ResolvedEntry extends EntryBase {
729
+ }
730
+
731
+ // src/entries/entry.ts
732
+ class Entry extends ResolvedEntry {
733
+ saving = false;
734
+ async save(options = {}) {
735
+ if (this.saving) {
736
+ throw new Error(`cannot save entry "${this.id}": a previous save() on this instance has not finished yet`);
737
+ }
738
+ this.saving = true;
739
+ try {
740
+ const payload = await this.context.transport.json({
741
+ method: "PUT",
742
+ path: ApiPath.entry(this.context.project, this.context.environment, this.context.collection, this.id),
743
+ query: { rev: this.rev, variables: "raw" },
744
+ body: this.fields,
745
+ ...options
746
+ });
747
+ this.adopt(payload);
748
+ return this;
749
+ } finally {
750
+ this.saving = false;
751
+ }
752
+ }
753
+ async refresh(options = {}) {
754
+ const payload = await this.context.transport.json({
755
+ method: "GET",
756
+ path: ApiPath.entry(this.context.project, this.context.environment, this.context.collection, this.id),
757
+ query: { variables: "raw" },
758
+ ...options
759
+ });
760
+ this.adopt(payload);
761
+ return this;
762
+ }
763
+ adopt(payload) {
764
+ this.rev = Number(payload.rev);
765
+ this.createdAt = new Date(payload.created_at);
766
+ this.updatedAt = new Date(payload.updated_at);
767
+ this.fields = EntryMapper.fieldsOf(payload);
768
+ }
769
+ }
770
+
771
+ // src/transport/page-payload.ts
772
+ class PagePayload {
773
+ static read(body) {
774
+ const rows = Array.isArray(body.data) ? body.data : Array.isArray(body.items) ? body.items : [];
775
+ return {
776
+ rows,
777
+ total: typeof body.total === "number" ? body.total : rows.length,
778
+ limit: typeof body.limit === "number" ? body.limit : undefined,
779
+ offset: typeof body.offset === "number" ? body.offset : undefined
780
+ };
781
+ }
782
+ }
783
+
784
+ // src/entries/entry-page.ts
785
+ class EntryPage extends Page {
786
+ loader;
787
+ constructor(rows, total, window, loader) {
788
+ super(rows, total, window);
789
+ this.loader = loader;
790
+ }
791
+ get entries() {
792
+ return this.rows;
793
+ }
794
+ next() {
795
+ const window = this.windowForNext();
796
+ return window ? this.loader(window) : Promise.resolve(null);
797
+ }
798
+ previous() {
799
+ const window = this.window.previous();
800
+ return window ? this.loader(window) : Promise.resolve(null);
801
+ }
802
+ }
803
+
804
+ // src/entries/entry-page-stream.ts
805
+ class EntryPageStream {
806
+ loadFirst;
807
+ options;
808
+ constructor(loadFirst, options = {}) {
809
+ this.loadFirst = loadFirst;
810
+ this.options = options;
811
+ }
812
+ async* [Symbol.asyncIterator]() {
813
+ let page = await this.loadFirst();
814
+ while (page) {
815
+ if (this.options.signal?.aborted) {
816
+ throw new RequestAbortedError("GET", "stream");
817
+ }
818
+ yield page;
819
+ const short = page.entries.length === 0 || page.entries.length < page.limit;
820
+ page = short ? null : await page.next();
821
+ }
822
+ }
823
+ }
824
+
825
+ // src/entries/entry-stream.ts
826
+ class EntryStream extends RowStream {
827
+ }
828
+
829
+ // src/entries/entry-reader.ts
830
+ class EntryReader {
831
+ context;
832
+ variables;
833
+ wrap;
834
+ constructor(context, variables, wrap) {
835
+ this.context = context;
836
+ this.variables = variables;
837
+ this.wrap = wrap;
838
+ }
839
+ async get(id, options = {}) {
840
+ const payload = await this.context.transport.json({
841
+ method: "GET",
842
+ path: ApiPath.entry(this.context.project, this.context.environment, this.context.collection, id),
843
+ query: { variables: this.variables },
844
+ ...options
845
+ });
846
+ return this.wrap(payload);
847
+ }
848
+ async list(query = {}, options = {}) {
849
+ const loader = (window2) => this.list({ ...query, limit: window2.limit, offset: window2.offset }, options);
850
+ const body = await this.context.transport.json({
851
+ method: "GET",
852
+ path: ApiPath.entries(this.context.project, this.context.environment, this.context.collection),
853
+ query: {
854
+ limit: query.limit,
855
+ offset: query.offset,
856
+ filter: query.where?.toJSON(),
857
+ sort: query.sort === undefined ? undefined : String(query.sort),
858
+ variables: this.variables
859
+ },
860
+ ...options
861
+ });
862
+ const page = PagePayload.read(body);
863
+ const window = new PageWindow(page.limit ?? query.limit ?? 50, page.offset ?? query.offset ?? 0);
864
+ return new EntryPage(page.rows.map((payload) => this.wrap(payload)), page.total, window, loader);
865
+ }
866
+ all(query = {}, options = {}) {
867
+ const loader = async (window) => {
868
+ const page = await this.list({ ...query, limit: window.limit, offset: window.offset }, options);
869
+ return { rows: [...page.entries], window: new PageWindow(page.limit, page.offset) };
870
+ };
871
+ return new EntryStream(loader, query.limit ?? 50, options);
872
+ }
873
+ pages(query = {}, options = {}) {
874
+ return new EntryPageStream(() => this.list(query, options), options);
875
+ }
876
+ }
877
+
878
+ // src/query/field-path.ts
879
+ class FieldPath {
880
+ static field(name) {
881
+ return `$.data.${name}`;
882
+ }
883
+ static each(name) {
884
+ return `$.data.${name}[*]`;
885
+ }
886
+ static meta(name) {
887
+ return `$.${name}`;
888
+ }
889
+ }
890
+
891
+ // src/query/filter-expression.ts
892
+ class FilterExpression {
893
+ node;
894
+ constructor(node) {
895
+ this.node = node;
896
+ }
897
+ and(other) {
898
+ return new FilterExpression({ op: "and", args: [this.node, other.node] });
899
+ }
900
+ or(other) {
901
+ return new FilterExpression({ op: "or", args: [this.node, other.node] });
902
+ }
903
+ not() {
904
+ return new FilterExpression({ op: "not", args: [this.node] });
905
+ }
906
+ toJSON() {
907
+ return this.node;
908
+ }
909
+ }
910
+
911
+ // src/query/filter-field.ts
912
+ class FilterField {
913
+ path;
914
+ constructor(path) {
915
+ this.path = path;
916
+ }
917
+ equals(value) {
918
+ return new FilterExpression({ op: "eq", path: this.path, value });
919
+ }
920
+ notEquals(value) {
921
+ return new FilterExpression({ op: "neq", path: this.path, value });
922
+ }
923
+ contains(value) {
924
+ return new FilterExpression({ op: "contains", path: this.path, value });
925
+ }
926
+ greaterThan(value) {
927
+ return new FilterExpression({ op: "gt", path: this.path, value });
928
+ }
929
+ atLeast(value) {
930
+ return new FilterExpression({ op: "gte", path: this.path, value });
931
+ }
932
+ lessThan(value) {
933
+ return new FilterExpression({ op: "lt", path: this.path, value });
934
+ }
935
+ atMost(value) {
936
+ return new FilterExpression({ op: "lte", path: this.path, value });
937
+ }
938
+ oneOf(values) {
939
+ return new FilterExpression({ op: "in", path: this.path, value: values });
940
+ }
941
+ exists() {
942
+ return new FilterExpression({ op: "exists", path: this.path });
943
+ }
944
+ }
945
+
946
+ // src/query/typed-filter.ts
947
+ class TypedFilter {
948
+ field(name) {
949
+ return new FilterField(FieldPath.field(name));
950
+ }
951
+ each(name) {
952
+ return new FilterField(FieldPath.each(name));
953
+ }
954
+ meta(name) {
955
+ return new FilterField(FieldPath.meta(name));
956
+ }
957
+ and(left, right) {
958
+ return left.and(right);
959
+ }
960
+ or(left, right) {
961
+ return left.or(right);
962
+ }
963
+ not(expression) {
964
+ return expression.not();
965
+ }
966
+ raw(node) {
967
+ return new FilterExpression(node);
968
+ }
969
+ }
970
+
971
+ // src/scope/rename-report.ts
972
+ class RenameReport {
973
+ id;
974
+ from;
975
+ to;
976
+ rewrittenClaims;
977
+ patternAffectedClaims;
978
+ constructor(id, from, to, rewrittenClaims, patternAffectedClaims) {
979
+ this.id = id;
980
+ this.from = from;
981
+ this.to = to;
982
+ this.rewrittenClaims = rewrittenClaims;
983
+ this.patternAffectedClaims = patternAffectedClaims;
984
+ }
985
+ static fromWire(payload) {
986
+ return new RenameReport(payload.id, payload.from, payload.to, payload.rewritten_claims, payload.pattern_affected_claims);
987
+ }
988
+ }
989
+
990
+ // src/search/search-page.ts
991
+ class SearchPage extends Page {
992
+ loader;
993
+ engine;
994
+ constructor(rows, total, window, truncated, engine, loader) {
995
+ super(rows, total, window, truncated);
996
+ this.loader = loader;
997
+ this.engine = engine;
998
+ }
999
+ get hits() {
1000
+ return this.rows;
1001
+ }
1002
+ next() {
1003
+ const window = this.windowForNext();
1004
+ return window ? this.loader(window) : Promise.resolve(null);
1005
+ }
1006
+ previous() {
1007
+ const window = this.window.previous();
1008
+ return window ? this.loader(window) : Promise.resolve(null);
1009
+ }
1010
+ }
1011
+
1012
+ // src/search/search.ts
1013
+ class Search {
1014
+ transport;
1015
+ reach;
1016
+ constructor(transport, reach) {
1017
+ this.transport = transport;
1018
+ this.reach = reach;
1019
+ }
1020
+ async run(query, options = {}) {
1021
+ const loader = (window2) => this.run({ ...query, limit: window2.limit, offset: window2.offset }, options);
1022
+ const body = await this.transport.json({
1023
+ method: "GET",
1024
+ path: this.reach.path,
1025
+ query: {
1026
+ q: query.query,
1027
+ filter: query.where?.toJSON(),
1028
+ sort: query.sort === undefined ? undefined : String(query.sort),
1029
+ limit: query.limit,
1030
+ offset: query.offset
1031
+ },
1032
+ ...options
1033
+ });
1034
+ const page = PagePayload.read(body);
1035
+ const window = new PageWindow(page.limit ?? query.limit ?? 50, page.offset ?? query.offset ?? 0);
1036
+ const truncated = body.truncated === true;
1037
+ const engine = body.engine;
1038
+ const hits = page.rows.map((hit) => this.toHit(hit));
1039
+ return new SearchPage(hits, page.total, window, truncated, engine, loader);
1040
+ }
1041
+ toHit(payload) {
1042
+ return {
1043
+ project: payload.project,
1044
+ environment: payload.env,
1045
+ collection: payload.collection,
1046
+ entry: new ResolvedEntry({ transport: this.transport, project: payload.project, environment: payload.env, collection: payload.collection }, payload.entry),
1047
+ snippets: payload.snippets
1048
+ };
1049
+ }
1050
+ }
1051
+
1052
+ // src/search/search-reach.ts
1053
+ class SearchReach {
1054
+ path;
1055
+ constructor(path) {
1056
+ this.path = path;
1057
+ }
1058
+ static collection(project, environment, name) {
1059
+ return new SearchReach(ApiPath.collectionSearch(project, environment, name));
1060
+ }
1061
+ static environment(project, environment) {
1062
+ return new SearchReach(ApiPath.environmentSearch(project, environment));
1063
+ }
1064
+ static instance() {
1065
+ return new SearchReach(ApiPath.instanceSearch());
1066
+ }
1067
+ }
1068
+
1069
+ // src/collections/collection-schema.ts
1070
+ class CollectionSchema {
1071
+ scope;
1072
+ name;
1073
+ constructor(scope, name) {
1074
+ this.scope = scope;
1075
+ this.name = name;
1076
+ }
1077
+ async get(options = {}) {
1078
+ return this.scope.transport.json({
1079
+ method: "GET",
1080
+ path: ApiPath.collectionSchema(this.scope.project, this.scope.environment, this.name),
1081
+ ...options
1082
+ });
1083
+ }
1084
+ async put(schema, options = {}) {
1085
+ return this.scope.transport.json({
1086
+ method: "PUT",
1087
+ path: ApiPath.collectionSchema(this.scope.project, this.scope.environment, this.name),
1088
+ body: schema,
1089
+ ...options
1090
+ });
1091
+ }
1092
+ async delete(options = {}) {
1093
+ await this.scope.transport.empty({
1094
+ method: "DELETE",
1095
+ path: ApiPath.collectionSchema(this.scope.project, this.scope.environment, this.name),
1096
+ query: { force: options.force || undefined },
1097
+ signal: options.signal,
1098
+ timeoutMilliseconds: options.timeoutMilliseconds
1099
+ });
1100
+ }
1101
+ }
1102
+
1103
+ // src/collections/collection-handle.ts
1104
+ class CollectionHandle {
1105
+ scope;
1106
+ name;
1107
+ filter = new TypedFilter;
1108
+ schema;
1109
+ editable;
1110
+ context;
1111
+ resolved;
1112
+ constructor(scope, name) {
1113
+ this.scope = scope;
1114
+ this.name = name;
1115
+ this.schema = new CollectionSchema(scope, name);
1116
+ this.context = {
1117
+ transport: scope.transport,
1118
+ project: scope.project,
1119
+ environment: scope.environment,
1120
+ collection: name
1121
+ };
1122
+ this.resolved = new EntryReader(this.context, undefined, (payload) => new ResolvedEntry(this.context, payload));
1123
+ this.editable = new EntryReader(this.context, "raw", (payload) => new Entry(this.context, payload));
1124
+ }
1125
+ get(id, options = {}) {
1126
+ return this.resolved.get(id, options);
1127
+ }
1128
+ edit(id, options = {}) {
1129
+ return this.editable.get(id, options);
1130
+ }
1131
+ list(query = {}, options = {}) {
1132
+ return this.resolved.list(query, options);
1133
+ }
1134
+ all(query = {}, options = {}) {
1135
+ return this.resolved.all(query, options);
1136
+ }
1137
+ pages(query = {}, options = {}) {
1138
+ return this.resolved.pages(query, options);
1139
+ }
1140
+ create(fields, options = {}) {
1141
+ return this.write("POST", ApiPath.entries(this.scope.project, this.scope.environment, this.name), fields, undefined, options);
1142
+ }
1143
+ replace(id, rev, fields, options = {}) {
1144
+ return this.write("PUT", ApiPath.entry(this.scope.project, this.scope.environment, this.name, id), fields, rev, options);
1145
+ }
1146
+ async delete(id, rev, options = {}) {
1147
+ await this.scope.transport.empty({
1148
+ method: "DELETE",
1149
+ path: ApiPath.entry(this.scope.project, this.scope.environment, this.name, id),
1150
+ query: { rev },
1151
+ ...options
1152
+ });
1153
+ }
1154
+ search(query, options = {}) {
1155
+ return new Search(this.scope.transport, SearchReach.collection(this.scope.project, this.scope.environment, this.name)).run(query, options);
1156
+ }
1157
+ async rename(name, options = {}) {
1158
+ const payload = await this.scope.transport.json({
1159
+ method: "PATCH",
1160
+ path: ApiPath.collection(this.scope.project, this.scope.environment, this.name),
1161
+ query: { dry_run: options.dryRun || undefined, expected_id: options.expectedId },
1162
+ body: { name },
1163
+ signal: options.signal,
1164
+ timeoutMilliseconds: options.timeoutMilliseconds
1165
+ });
1166
+ return RenameReport.fromWire(payload);
1167
+ }
1168
+ async write(method, path, fields, rev, options) {
1169
+ const payload = await this.scope.transport.json({
1170
+ method,
1171
+ path,
1172
+ query: { rev, variables: "raw" },
1173
+ body: fields,
1174
+ ...options
1175
+ });
1176
+ return new Entry(this.context, payload);
1177
+ }
1178
+ }
1179
+
1180
+ // src/collections/reserved-field-names.ts
1181
+ class ReservedFieldNames {
1182
+ static all = ["id", "rev", "seq", "created_at", "updated_at"];
1183
+ static isReserved(name) {
1184
+ return ReservedFieldNames.all.includes(name);
1185
+ }
1186
+ }
1187
+
1188
+ // src/collections/collections.ts
1189
+ class Collections {
1190
+ scope;
1191
+ constructor(scope) {
1192
+ this.scope = scope;
1193
+ }
1194
+ async list(options = {}) {
1195
+ const body = await this.scope.transport.json({
1196
+ method: "GET",
1197
+ path: ApiPath.collections(this.scope.project, this.scope.environment),
1198
+ ...options
1199
+ });
1200
+ return body.items.map(Collections.toSummary);
1201
+ }
1202
+ async create(name, schema, options = {}) {
1203
+ Collections.warnOnReservedFields(schema);
1204
+ return this.scope.transport.json({
1205
+ method: "POST",
1206
+ path: ApiPath.collections(this.scope.project, this.scope.environment),
1207
+ body: { name, schema },
1208
+ ...options
1209
+ });
1210
+ }
1211
+ static toSummary(payload) {
1212
+ return {
1213
+ id: payload.id,
1214
+ name: payload.name,
1215
+ entries: payload.entries,
1216
+ requiresAuth: payload.requires_auth,
1217
+ createdAt: new Date(payload.created_at),
1218
+ updatedAt: new Date(payload.updated_at)
1219
+ };
1220
+ }
1221
+ static warnOnReservedFields(schema) {
1222
+ for (const name of Object.keys(schema.properties ?? {})) {
1223
+ if (ReservedFieldNames.isReserved(name)) {
1224
+ console.warn(`@org-quicko/silo-client: collection schema declares reserved field "${name}", which the server never returns`);
1225
+ }
1226
+ }
1227
+ }
1228
+ }
1229
+
1230
+ // src/variables/environment-variables.ts
1231
+ class EnvironmentVariables {
1232
+ scope;
1233
+ constructor(scope) {
1234
+ this.scope = scope;
1235
+ }
1236
+ async list(options = {}) {
1237
+ const body = await this.scope.transport.json({
1238
+ method: "GET",
1239
+ path: ApiPath.environmentVariables(this.scope.project, this.scope.environment),
1240
+ ...options
1241
+ });
1242
+ return body.items.map(Variable.fromWire);
1243
+ }
1244
+ async set(name, value, options = {}) {
1245
+ const payload = await this.scope.transport.json({
1246
+ method: "PUT",
1247
+ path: ApiPath.environmentVariable(this.scope.project, this.scope.environment, name),
1248
+ body: { value },
1249
+ ...options
1250
+ });
1251
+ return Variable.fromWire(payload);
1252
+ }
1253
+ async unset(name, options = {}) {
1254
+ const payload = await this.scope.transport.json({
1255
+ method: "DELETE",
1256
+ path: ApiPath.environmentVariable(this.scope.project, this.scope.environment, name),
1257
+ ...options
1258
+ });
1259
+ return Variable.fromWire(payload);
1260
+ }
1261
+ }
1262
+
1263
+ // src/scope/environment-handle.ts
1264
+ class EnvironmentHandle {
1265
+ scope;
1266
+ name;
1267
+ project;
1268
+ collections;
1269
+ variables;
1270
+ constructor(scope) {
1271
+ this.scope = scope;
1272
+ this.name = scope.environment;
1273
+ this.project = scope.project;
1274
+ this.collections = new Collections(scope);
1275
+ this.variables = new EnvironmentVariables(scope);
1276
+ }
1277
+ collection(name) {
1278
+ return new CollectionHandle(this.scope, name);
1279
+ }
1280
+ async schemas(options = {}) {
1281
+ const body = await this.scope.transport.json({
1282
+ method: "GET",
1283
+ path: ApiPath.schemas(this.scope.project, this.scope.environment),
1284
+ ...options
1285
+ });
1286
+ return body.items;
1287
+ }
1288
+ async search(query, options = {}) {
1289
+ return new Search(this.scope.transport, SearchReach.environment(this.scope.project, this.scope.environment)).run(query, options);
1290
+ }
1291
+ async rename(name, options = {}) {
1292
+ const payload = await this.scope.transport.json({
1293
+ method: "PATCH",
1294
+ path: ApiPath.environment(this.scope.project, this.scope.environment),
1295
+ query: { dry_run: options.dryRun || undefined, expected_id: options.expectedId },
1296
+ body: { name },
1297
+ signal: options.signal,
1298
+ timeoutMilliseconds: options.timeoutMilliseconds
1299
+ });
1300
+ return RenameReport.fromWire(payload);
1301
+ }
1302
+ async delete(options = {}) {
1303
+ await this.scope.transport.empty({
1304
+ method: "DELETE",
1305
+ path: ApiPath.environment(this.scope.project, this.scope.environment),
1306
+ query: { force: options.force || undefined },
1307
+ signal: options.signal,
1308
+ timeoutMilliseconds: options.timeoutMilliseconds
1309
+ });
1310
+ }
1311
+ }
1312
+
1313
+ // src/scope/environments.ts
1314
+ class Environments {
1315
+ transport;
1316
+ project;
1317
+ constructor(transport, project) {
1318
+ this.transport = transport;
1319
+ this.project = project;
1320
+ }
1321
+ async list(options = {}) {
1322
+ const body = await this.transport.json({
1323
+ method: "GET",
1324
+ path: ApiPath.environments(this.project),
1325
+ ...options
1326
+ });
1327
+ return body.items.map((item) => ({ id: item.id, name: item.name }));
1328
+ }
1329
+ async create(name, options = {}) {
1330
+ const payload = await this.transport.json({
1331
+ method: "POST",
1332
+ path: ApiPath.environments(this.project),
1333
+ body: { id: name },
1334
+ ...options
1335
+ });
1336
+ return { id: payload.id, name: payload.name };
1337
+ }
1338
+ }
1339
+
1340
+ // src/scope/scope-reference.ts
1341
+ class ScopeReference {
1342
+ transport;
1343
+ project;
1344
+ environment;
1345
+ constructor(transport, project, environment) {
1346
+ this.transport = transport;
1347
+ this.project = project;
1348
+ this.environment = environment;
1349
+ }
1350
+ }
1351
+
1352
+ // src/scope/project-handle.ts
1353
+ class ProjectHandle {
1354
+ transport;
1355
+ name;
1356
+ environments;
1357
+ variables;
1358
+ constructor(transport, name) {
1359
+ this.transport = transport;
1360
+ this.name = name;
1361
+ this.environments = new Environments(transport, name);
1362
+ this.variables = new ProjectVariables(transport, name);
1363
+ }
1364
+ environment(name) {
1365
+ return new EnvironmentHandle(new ScopeReference(this.transport, this.name, name));
1366
+ }
1367
+ async rename(name, options = {}) {
1368
+ const payload = await this.transport.json({
1369
+ method: "PATCH",
1370
+ path: ApiPath.project(this.name),
1371
+ query: { dry_run: options.dryRun || undefined, expected_id: options.expectedId },
1372
+ body: { name },
1373
+ signal: options.signal,
1374
+ timeoutMilliseconds: options.timeoutMilliseconds
1375
+ });
1376
+ return RenameReport.fromWire(payload);
1377
+ }
1378
+ async delete(options = {}) {
1379
+ await this.transport.empty({
1380
+ method: "DELETE",
1381
+ path: ApiPath.project(this.name),
1382
+ query: { force: options.force || undefined },
1383
+ signal: options.signal,
1384
+ timeoutMilliseconds: options.timeoutMilliseconds
1385
+ });
1386
+ }
1387
+ }
1388
+
1389
+ // src/scope/projects.ts
1390
+ class Projects {
1391
+ transport;
1392
+ constructor(transport) {
1393
+ this.transport = transport;
1394
+ }
1395
+ async list(options = {}) {
1396
+ const body = await this.transport.json({
1397
+ method: "GET",
1398
+ path: ApiPath.projects(),
1399
+ ...options
1400
+ });
1401
+ return body.items.map((item) => ({ id: item.id, name: item.name }));
1402
+ }
1403
+ async create(name, options = {}) {
1404
+ const payload = await this.transport.json({
1405
+ method: "POST",
1406
+ path: ApiPath.projects(),
1407
+ body: { id: name },
1408
+ ...options
1409
+ });
1410
+ return { id: payload.id, name: payload.name };
1411
+ }
1412
+ }
1413
+
1414
+ // src/errors/silo-error.ts
1415
+ class SiloError extends Error {
1416
+ status;
1417
+ code;
1418
+ method;
1419
+ path;
1420
+ constructor(status, code, message, method, path) {
1421
+ super(message);
1422
+ this.name = "SiloError";
1423
+ this.status = status;
1424
+ this.code = code;
1425
+ this.method = method;
1426
+ this.path = path;
1427
+ Object.setPrototypeOf(this, SiloError.prototype);
1428
+ }
1429
+ }
1430
+
1431
+ // src/errors/conflict-error.ts
1432
+ class ConflictError extends SiloError {
1433
+ constructor(message, method, path, code = "conflict") {
1434
+ super(409, code, message, method, path);
1435
+ this.name = "ConflictError";
1436
+ Object.setPrototypeOf(this, ConflictError.prototype);
1437
+ }
1438
+ }
1439
+
1440
+ // src/errors/forbidden-error.ts
1441
+ class ForbiddenError extends SiloError {
1442
+ constructor(message, method, path) {
1443
+ super(403, "forbidden", message, method, path);
1444
+ this.name = "ForbiddenError";
1445
+ Object.setPrototypeOf(this, ForbiddenError.prototype);
1446
+ }
1447
+ }
1448
+
1449
+ // src/errors/internal-error.ts
1450
+ class InternalError extends SiloError {
1451
+ constructor(message, method, path) {
1452
+ super(500, "internal", message, method, path);
1453
+ this.name = "InternalError";
1454
+ Object.setPrototypeOf(this, InternalError.prototype);
1455
+ }
1456
+ }
1457
+
1458
+ // src/errors/media-delete-stalled-error.ts
1459
+ class MediaDeleteStalledError extends SiloError {
1460
+ remedy;
1461
+ constructor(message, method, path, remedy) {
1462
+ super(500, "media_delete_stalled", message, method, path);
1463
+ this.name = "MediaDeleteStalledError";
1464
+ this.remedy = remedy;
1465
+ Object.setPrototypeOf(this, MediaDeleteStalledError.prototype);
1466
+ }
1467
+ static fromWireDetails(message, method, path, details) {
1468
+ const object = details && typeof details === "object" ? details : {};
1469
+ const remedy = typeof object.remedy === "string" ? object.remedy : "";
1470
+ return new MediaDeleteStalledError(message, method, path, remedy);
1471
+ }
1472
+ }
1473
+
1474
+ // src/errors/media-in-use-error.ts
1475
+ class MediaInUseError extends ConflictError {
1476
+ usageCount;
1477
+ visibleCount;
1478
+ visibleCapped;
1479
+ referrers;
1480
+ constructor(message, method, path, usageCount, visibleCount, visibleCapped, referrers) {
1481
+ super(message, method, path, "media_in_use");
1482
+ this.name = "MediaInUseError";
1483
+ this.usageCount = usageCount;
1484
+ this.visibleCount = visibleCount;
1485
+ this.visibleCapped = visibleCapped;
1486
+ this.referrers = referrers;
1487
+ Object.setPrototypeOf(this, MediaInUseError.prototype);
1488
+ }
1489
+ static fromWireDetails(message, method, path, details) {
1490
+ const object = details && typeof details === "object" ? details : {};
1491
+ const referrers = Array.isArray(object.referrers) ? object.referrers.map((referrer) => MediaAssetMapper.toUsage(referrer)) : [];
1492
+ return new MediaInUseError(message, method, path, typeof object.usage_count === "number" ? object.usage_count : 0, typeof object.visible_count === "number" ? object.visible_count : 0, object.visible_capped === true, referrers);
1493
+ }
1494
+ }
1495
+
1496
+ // src/errors/not-found-error.ts
1497
+ class NotFoundError extends SiloError {
1498
+ constructor(message, method, path) {
1499
+ super(404, "not_found", message, method, path);
1500
+ this.name = "NotFoundError";
1501
+ Object.setPrototypeOf(this, NotFoundError.prototype);
1502
+ }
1503
+ }
1504
+
1505
+ // src/errors/unauthorized-error.ts
1506
+ class UnauthorizedError extends SiloError {
1507
+ constructor(message, method, path) {
1508
+ super(401, "unauthorized", message, method, path);
1509
+ this.name = "UnauthorizedError";
1510
+ Object.setPrototypeOf(this, UnauthorizedError.prototype);
1511
+ }
1512
+ }
1513
+
1514
+ // src/errors/validation-failed-error.ts
1515
+ class ValidationFailedError extends SiloError {
1516
+ details;
1517
+ constructor(message, method, path, details) {
1518
+ super(400, "validation_failed", message, method, path);
1519
+ this.name = "ValidationFailedError";
1520
+ this.details = details;
1521
+ Object.setPrototypeOf(this, ValidationFailedError.prototype);
1522
+ }
1523
+ static fromWireDetails(message, method, path, details) {
1524
+ const array = Array.isArray(details) ? details : [];
1525
+ return new ValidationFailedError(message, method, path, array);
1526
+ }
1527
+ }
1528
+
1529
+ // src/errors/error-factory.ts
1530
+ class ErrorFactory {
1531
+ static fromResponseBody(status, method, path, rawBody) {
1532
+ const payload = ErrorFactory.parse(rawBody);
1533
+ if (!payload) {
1534
+ const message2 = rawBody.trim().length > 0 ? rawBody : `request failed with status ${status}`;
1535
+ return ErrorFactory.byStatus(status, message2, method, path);
1536
+ }
1537
+ const { code, message, details } = payload.error;
1538
+ switch (code) {
1539
+ case "validation_failed":
1540
+ return ValidationFailedError.fromWireDetails(message, method, path, details);
1541
+ case "unauthorized":
1542
+ return new UnauthorizedError(message, method, path);
1543
+ case "forbidden":
1544
+ return new ForbiddenError(message, method, path);
1545
+ case "not_found":
1546
+ return new NotFoundError(message, method, path);
1547
+ case "conflict":
1548
+ return new ConflictError(message, method, path);
1549
+ case "media_in_use":
1550
+ return MediaInUseError.fromWireDetails(message, method, path, details);
1551
+ case "media_delete_stalled":
1552
+ return MediaDeleteStalledError.fromWireDetails(message, method, path, details);
1553
+ case "internal":
1554
+ return new InternalError(message, method, path);
1555
+ default:
1556
+ return ErrorFactory.byStatus(status, message, method, path);
1557
+ }
1558
+ }
1559
+ static byStatus(status, message, method, path) {
1560
+ switch (status) {
1561
+ case 400:
1562
+ return new ValidationFailedError(message, method, path, []);
1563
+ case 401:
1564
+ return new UnauthorizedError(message, method, path);
1565
+ case 403:
1566
+ return new ForbiddenError(message, method, path);
1567
+ case 404:
1568
+ return new NotFoundError(message, method, path);
1569
+ case 409:
1570
+ return new ConflictError(message, method, path);
1571
+ default:
1572
+ return new SiloError(status, "unknown", message, method, path);
1573
+ }
1574
+ }
1575
+ static parse(rawBody) {
1576
+ if (!rawBody)
1577
+ return null;
1578
+ try {
1579
+ const parsed = JSON.parse(rawBody);
1580
+ if (parsed && typeof parsed === "object" && "error" in parsed)
1581
+ return parsed;
1582
+ return null;
1583
+ } catch {
1584
+ return null;
1585
+ }
1586
+ }
1587
+ }
1588
+
1589
+ // src/errors/network-error.ts
1590
+ class NetworkError extends Error {
1591
+ method;
1592
+ path;
1593
+ constructor(method, path, cause) {
1594
+ super(`network error on ${method} ${path}: the request never reached the server`, { cause });
1595
+ this.name = "NetworkError";
1596
+ this.method = method;
1597
+ this.path = path;
1598
+ Object.setPrototypeOf(this, NetworkError.prototype);
1599
+ }
1600
+ }
1601
+
1602
+ // src/errors/timeout-error.ts
1603
+ class TimeoutError extends Error {
1604
+ method;
1605
+ path;
1606
+ timeoutMilliseconds;
1607
+ constructor(method, path, timeoutMilliseconds) {
1608
+ super(`${method} ${path} timed out after ${timeoutMilliseconds}ms`);
1609
+ this.name = "TimeoutError";
1610
+ this.method = method;
1611
+ this.path = path;
1612
+ this.timeoutMilliseconds = timeoutMilliseconds;
1613
+ Object.setPrototypeOf(this, TimeoutError.prototype);
1614
+ }
1615
+ }
1616
+
1617
+ // src/transport/abort-signals.ts
1618
+ class AbortSignals {
1619
+ signal;
1620
+ reason;
1621
+ cleanups = [];
1622
+ constructor(callerSignal, timeoutMilliseconds) {
1623
+ const controller = new AbortController;
1624
+ const fire = (reason) => {
1625
+ if (this.reason)
1626
+ return;
1627
+ this.reason = reason;
1628
+ controller.abort();
1629
+ };
1630
+ if (callerSignal) {
1631
+ if (callerSignal.aborted) {
1632
+ fire("caller");
1633
+ } else {
1634
+ const onAbort = () => fire("caller");
1635
+ callerSignal.addEventListener("abort", onAbort);
1636
+ this.cleanups.push(() => callerSignal.removeEventListener("abort", onAbort));
1637
+ }
1638
+ }
1639
+ if (timeoutMilliseconds !== undefined) {
1640
+ const timer = setTimeout(() => fire("timeout"), timeoutMilliseconds);
1641
+ this.cleanups.push(() => clearTimeout(timer));
1642
+ }
1643
+ this.signal = controller.signal;
1644
+ }
1645
+ firedBy() {
1646
+ return this.reason;
1647
+ }
1648
+ dispose() {
1649
+ for (const cleanup of this.cleanups.splice(0))
1650
+ cleanup();
1651
+ }
1652
+ }
1653
+
1654
+ // src/transport/query-string.ts
1655
+ class QueryString {
1656
+ static build(query) {
1657
+ if (!query)
1658
+ return "";
1659
+ const parts = [];
1660
+ for (const [key, value] of Object.entries(query)) {
1661
+ if (value === undefined || value === null)
1662
+ continue;
1663
+ const encoded = typeof value === "object" ? JSON.stringify(value) : String(value);
1664
+ parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(encoded)}`);
1665
+ }
1666
+ return parts.length > 0 ? `?${parts.join("&")}` : "";
1667
+ }
1668
+ }
1669
+
1670
+ // src/errors/invalid-response-error.ts
1671
+ class InvalidResponseError extends Error {
1672
+ method;
1673
+ path;
1674
+ contentType;
1675
+ constructor(method, path, contentType) {
1676
+ super(`${method} ${path} answered with content-type "${contentType}", not the JSON this route promises`);
1677
+ this.name = "InvalidResponseError";
1678
+ this.method = method;
1679
+ this.path = path;
1680
+ this.contentType = contentType;
1681
+ Object.setPrototypeOf(this, InvalidResponseError.prototype);
1682
+ }
1683
+ }
1684
+
1685
+ // src/transport/response-decoder.ts
1686
+ class ResponseDecoder {
1687
+ static async decode(response, request, expectJson) {
1688
+ if (response.status === 204)
1689
+ return;
1690
+ const contentType = response.headers.get("content-type") ?? "";
1691
+ if (contentType.includes("application/json")) {
1692
+ return response.json();
1693
+ }
1694
+ if (expectJson) {
1695
+ throw new InvalidResponseError(request.method, request.path, contentType);
1696
+ }
1697
+ return response.text();
1698
+ }
1699
+ }
1700
+
1701
+ // src/transport/transport.ts
1702
+ class Transport {
1703
+ url;
1704
+ key;
1705
+ headers;
1706
+ timeoutMilliseconds;
1707
+ fetchFunction;
1708
+ constructor(options) {
1709
+ this.url = Transport.normalizeUrl(options.url);
1710
+ this.key = options.key;
1711
+ this.headers = options.headers ?? {};
1712
+ this.timeoutMilliseconds = options.timeoutMilliseconds;
1713
+ this.fetchFunction = options.fetch ?? fetch;
1714
+ }
1715
+ async json(request) {
1716
+ const response = await this.execute(request);
1717
+ return await ResponseDecoder.decode(response, request, true);
1718
+ }
1719
+ async empty(request) {
1720
+ const response = await this.execute(request);
1721
+ await ResponseDecoder.decode(response, request, false);
1722
+ }
1723
+ async stream(request) {
1724
+ const response = await this.execute(request);
1725
+ return response.body;
1726
+ }
1727
+ async upload(request, form) {
1728
+ const response = await this.execute(request, form);
1729
+ return await ResponseDecoder.decode(response, request, true);
1730
+ }
1731
+ withKey(key) {
1732
+ return new Transport({ ...this.snapshot(), key });
1733
+ }
1734
+ withUrl(url) {
1735
+ return new Transport({ ...this.snapshot(), url });
1736
+ }
1737
+ snapshot() {
1738
+ return {
1739
+ url: this.url,
1740
+ key: this.key,
1741
+ headers: this.headers,
1742
+ timeoutMilliseconds: this.timeoutMilliseconds,
1743
+ fetch: this.fetchFunction
1744
+ };
1745
+ }
1746
+ async execute(request, form) {
1747
+ const abortSignals = new AbortSignals(request.signal, request.timeoutMilliseconds ?? this.timeoutMilliseconds);
1748
+ const url = `${this.url}${request.path}${QueryString.build(request.query)}`;
1749
+ let response;
1750
+ try {
1751
+ response = await this.fetchFunction(url, {
1752
+ method: request.method,
1753
+ headers: this.buildHeaders(request, Boolean(form)),
1754
+ body: form ?? (request.body === undefined ? undefined : JSON.stringify(request.body)),
1755
+ signal: abortSignals.signal
1756
+ });
1757
+ } catch (caught) {
1758
+ throw this.transportFailure(request, abortSignals, caught);
1759
+ } finally {
1760
+ abortSignals.dispose();
1761
+ }
1762
+ if (!response.ok) {
1763
+ throw ErrorFactory.fromResponseBody(response.status, request.method, request.path, await response.text());
1764
+ }
1765
+ return response;
1766
+ }
1767
+ transportFailure(request, abortSignals, caught) {
1768
+ const firedBy = abortSignals.firedBy();
1769
+ if (firedBy === "timeout") {
1770
+ return new TimeoutError(request.method, request.path, request.timeoutMilliseconds ?? this.timeoutMilliseconds ?? 0);
1771
+ }
1772
+ if (firedBy === "caller") {
1773
+ return new RequestAbortedError(request.method, request.path);
1774
+ }
1775
+ return new NetworkError(request.method, request.path, caught);
1776
+ }
1777
+ buildHeaders(request, isUpload) {
1778
+ const headers = { ...this.headers, ...request.headers };
1779
+ if (this.key)
1780
+ headers["Authorization"] = `Bearer ${this.key}`;
1781
+ if (!isUpload && request.body !== undefined && !("Content-Type" in headers)) {
1782
+ headers["Content-Type"] = "application/json";
1783
+ }
1784
+ return headers;
1785
+ }
1786
+ static normalizeUrl(url) {
1787
+ return url.replace(/\/+$/, "");
1788
+ }
1789
+ }
1790
+
1791
+ // src/silo.ts
1792
+ class Silo {
1793
+ projects;
1794
+ media;
1795
+ options;
1796
+ transport;
1797
+ constructor(options) {
1798
+ this.options = options;
1799
+ this.transport = new Transport({
1800
+ url: options.url,
1801
+ key: options.key,
1802
+ headers: options.headers,
1803
+ timeoutMilliseconds: options.timeoutMilliseconds,
1804
+ fetch: options.fetch
1805
+ });
1806
+ this.projects = new Projects(this.transport);
1807
+ this.media = new Media(this.transport);
1808
+ }
1809
+ project(name) {
1810
+ return new ProjectHandle(this.transport, name);
1811
+ }
1812
+ scope(project, environment) {
1813
+ return this.project(project).environment(environment);
1814
+ }
1815
+ search(query, options) {
1816
+ return new Search(this.transport, SearchReach.instance()).run(query, options);
1817
+ }
1818
+ health(options) {
1819
+ return this.transport.json({
1820
+ method: "GET",
1821
+ path: ApiPath.health(),
1822
+ signal: options?.signal,
1823
+ timeoutMilliseconds: options?.timeoutMilliseconds
1824
+ });
1825
+ }
1826
+ withKey(key) {
1827
+ return new Silo({ ...this.options, key });
1828
+ }
1829
+ withUrl(url) {
1830
+ return new Silo({ ...this.options, url });
1831
+ }
1832
+ }
1833
+ // src/transport/route-inventory.ts
1834
+ class RouteInventory {
1835
+ static Covered = [
1836
+ "GET /api/health",
1837
+ "GET /api/projects",
1838
+ "POST /api/projects",
1839
+ "PATCH /api/projects/:project",
1840
+ "DELETE /api/projects/:project",
1841
+ "GET /api/projects/:project/envs",
1842
+ "POST /api/projects/:project/envs",
1843
+ "PATCH /api/projects/:project/envs/:env",
1844
+ "DELETE /api/projects/:project/envs/:env",
1845
+ "POST /api/projects/:project/variables",
1846
+ "PATCH /api/projects/:project/variables/:name",
1847
+ "DELETE /api/projects/:project/variables/:name",
1848
+ "GET /api/projects/:project/envs/:env/variables",
1849
+ "PUT /api/projects/:project/envs/:env/variables/:name",
1850
+ "DELETE /api/projects/:project/envs/:env/variables/:name",
1851
+ "GET /api/projects/:project/envs/:env/collections",
1852
+ "POST /api/projects/:project/envs/:env/collections",
1853
+ "PATCH /api/projects/:project/envs/:env/collections/:name",
1854
+ "GET /api/projects/:project/envs/:env/schemas",
1855
+ "GET /api/projects/:project/envs/:env/collections/:name/schema",
1856
+ "PUT /api/projects/:project/envs/:env/collections/:name/schema",
1857
+ "DELETE /api/projects/:project/envs/:env/collections/:name/schema",
1858
+ "GET /api/projects/:project/envs/:env/collections/:name",
1859
+ "POST /api/projects/:project/envs/:env/collections/:name",
1860
+ "GET /api/projects/:project/envs/:env/collections/:name/:id",
1861
+ "PUT /api/projects/:project/envs/:env/collections/:name/:id",
1862
+ "DELETE /api/projects/:project/envs/:env/collections/:name/:id",
1863
+ "GET /api/projects/:project/envs/:env/collections/:name/search",
1864
+ "GET /api/projects/:project/envs/:env/search",
1865
+ "GET /api/search",
1866
+ "GET /api/media",
1867
+ "POST /api/media",
1868
+ "GET /api/media/extensions",
1869
+ "GET /api/media/:id",
1870
+ "PATCH /api/media/:id",
1871
+ "DELETE /api/media/:id",
1872
+ "GET /api/media/:id/usages",
1873
+ "POST /api/media/delete",
1874
+ "GET /api/media/folders",
1875
+ "POST /api/media/folders",
1876
+ "PATCH /api/media/folders",
1877
+ "DELETE /api/media/folders"
1878
+ ];
1879
+ static OutOfScope = {
1880
+ "GET /api/session": "key introspection, an operator surface",
1881
+ "GET /api/keys": "keys and claims are an operator surface",
1882
+ "POST /api/keys": "keys and claims are an operator surface",
1883
+ "DELETE /api/keys/:id": "keys and claims are an operator surface",
1884
+ "GET /api/audit": "an operator surface",
1885
+ "GET /api/observability": "an operator surface",
1886
+ "GET /api/settings": "an operator surface",
1887
+ "PUT /api/settings/:table": "an operator surface",
1888
+ "GET /api/export": "transfer is an operator surface",
1889
+ "POST /api/import": "transfer is an operator surface",
1890
+ "POST /api/copy": "transfer is an operator surface",
1891
+ "POST /api/projects/:project/envs/:env/copy": "scope-to-scope copy is transfer",
1892
+ "POST /api/search/reindex": "rebuilding the index is an operator action",
1893
+ "POST /api/media/purge": "emptying the library is an operator action",
1894
+ "POST /api/media/reconcile": "an operator action",
1895
+ "GET /api/media/storage": "media configuration is an operator surface",
1896
+ "PUT /api/media/storage": "media configuration is an operator surface",
1897
+ "GET /api/media/settings": "media configuration is an operator surface",
1898
+ "PUT /api/media/settings": "media configuration is an operator surface",
1899
+ "GET /api/plugins": "plugins are an operator surface",
1900
+ "GET /api/plugins/:name": "plugins are an operator surface",
1901
+ "GET /api/plugins/:name/ui": "a plugin's admin panel, rendered by the admin UI",
1902
+ "DELETE /api/plugins/:name": "plugins are an operator surface",
1903
+ "POST /api/plugins/install": "plugins are an operator surface",
1904
+ "ALL /api/ext/*": "routes a plugin contributes; their shapes are the plugin's, not silo's",
1905
+ "PUT /api/plugins/:name/grant": "plugins are an operator surface",
1906
+ "DELETE /api/plugins/:name/grant": "plugins are an operator surface",
1907
+ "POST /api/plugins/:name/enable": "plugins are an operator surface",
1908
+ "POST /api/plugins/:name/disable": "plugins are an operator surface",
1909
+ "POST /api/plugins/:name/restart": "plugins are an operator surface",
1910
+ "PATCH /api/plugins/:name/config": "plugins are an operator surface",
1911
+ "DELETE /api/plugins/:name/config": "plugins are an operator surface",
1912
+ "POST /api/plugins/rescan": "plugins are an operator surface",
1913
+ "GET /media/:idOrKey": "a browser URL, not a call: use asset.url"
1914
+ };
1915
+ static accountsFor(route) {
1916
+ return RouteInventory.Covered.includes(route) || route in RouteInventory.OutOfScope;
1917
+ }
1918
+ }
1919
+ // src/query/filter.ts
1920
+ class Filter {
1921
+ static field(name) {
1922
+ return new FilterField(FieldPath.field(name));
1923
+ }
1924
+ static each(name) {
1925
+ return new FilterField(FieldPath.each(name));
1926
+ }
1927
+ static meta(name) {
1928
+ return new FilterField(FieldPath.meta(name));
1929
+ }
1930
+ static and(left, right) {
1931
+ return left.and(right);
1932
+ }
1933
+ static or(left, right) {
1934
+ return left.or(right);
1935
+ }
1936
+ static not(expression) {
1937
+ return expression.not();
1938
+ }
1939
+ static raw(node) {
1940
+ return new FilterExpression(node);
1941
+ }
1942
+ }
1943
+ // src/query/sort-term.ts
1944
+ class SortTerm {
1945
+ path;
1946
+ direction;
1947
+ constructor(path, direction = "asc") {
1948
+ this.path = path;
1949
+ this.direction = direction;
1950
+ }
1951
+ ascending() {
1952
+ return new SortTerm(this.path, "asc");
1953
+ }
1954
+ descending() {
1955
+ return new SortTerm(this.path, "desc");
1956
+ }
1957
+ toString() {
1958
+ return this.direction === "desc" ? `-${this.path}` : this.path;
1959
+ }
1960
+ }
1961
+
1962
+ // src/query/sort.ts
1963
+ class Sort {
1964
+ static by(name) {
1965
+ return new SortTerm(FieldPath.field(name));
1966
+ }
1967
+ static meta(name) {
1968
+ return new SortTerm(FieldPath.meta(name));
1969
+ }
1970
+ static recentlyUpdated() {
1971
+ return Sort.meta("updated_at").descending();
1972
+ }
1973
+ static recentlyCreated() {
1974
+ return Sort.meta("created_at").descending();
1975
+ }
1976
+ static of(...terms) {
1977
+ return terms.map((term) => term.toString()).join(",");
1978
+ }
1979
+ }
1980
+ // src/query/filter-operator.ts
1981
+ var FilterOperators = Object.freeze([
1982
+ "eq",
1983
+ "neq",
1984
+ "gt",
1985
+ "gte",
1986
+ "lt",
1987
+ "lte",
1988
+ "in",
1989
+ "contains",
1990
+ "exists",
1991
+ "and",
1992
+ "or",
1993
+ "not"
1994
+ ]);
1995
+ export {
1996
+ Variable,
1997
+ ValidationFailedError,
1998
+ UnauthorizedError,
1999
+ TypedFilter,
2000
+ TimeoutError,
2001
+ SortTerm,
2002
+ Sort,
2003
+ SiloError,
2004
+ Silo,
2005
+ SearchReach,
2006
+ SearchPage,
2007
+ Search,
2008
+ RowStream,
2009
+ RouteInventory,
2010
+ ResolvedEntry,
2011
+ ReservedFieldNames,
2012
+ RequestAbortedError,
2013
+ RenameReport,
2014
+ Projects,
2015
+ ProjectVariables,
2016
+ ProjectHandle,
2017
+ PageWindow,
2018
+ Page,
2019
+ NotFoundError,
2020
+ NetworkError,
2021
+ MediaUsagePage,
2022
+ MediaStream,
2023
+ MediaReference,
2024
+ MediaPageStream,
2025
+ MediaPage,
2026
+ MediaInUseError,
2027
+ MediaFolders,
2028
+ MediaDeleteStalledError,
2029
+ MediaDeleteReport,
2030
+ MediaAsset,
2031
+ Media,
2032
+ InvalidResponseError,
2033
+ InternalError,
2034
+ ForbiddenError,
2035
+ FilterOperators,
2036
+ FilterField,
2037
+ FilterExpression,
2038
+ Filter,
2039
+ FieldPath,
2040
+ Environments,
2041
+ EnvironmentVariables,
2042
+ EnvironmentHandle,
2043
+ EntryStream,
2044
+ EntryReader,
2045
+ EntryPageStream,
2046
+ EntryPage,
2047
+ EntryBase,
2048
+ Entry,
2049
+ ConflictError,
2050
+ Collections,
2051
+ CollectionSchema,
2052
+ CollectionHandle
2053
+ };