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