@01.software/sdk 0.70.1 → 0.72.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +143 -0
- package/MIGRATION.md +28 -0
- package/README.md +253 -11
- package/dist/client.cjs +396 -26
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +7 -6
- package/dist/client.d.ts +7 -6
- package/dist/client.js +396 -26
- package/dist/client.js.map +1 -1
- package/dist/{collection-client-BHLStm1K.d.cts → collection-client-B3CnqMDQ.d.cts} +14 -18
- package/dist/{collection-client-B1FSJ24_.d.ts → collection-client-uOgS_1bC.d.ts} +14 -18
- package/dist/{const-ty8u0TDI.d.ts → const-BJBK7jBl.d.ts} +1 -1
- package/dist/{const-BfQfV-rr.d.cts → const-_ZfJjRQG.d.cts} +1 -1
- package/dist/embedded-admin/server.cjs +117 -2
- package/dist/embedded-admin/server.cjs.map +1 -1
- package/dist/embedded-admin/server.d.cts +30 -2
- package/dist/embedded-admin/server.d.ts +30 -2
- package/dist/embedded-admin/server.js +117 -2
- package/dist/embedded-admin/server.js.map +1 -1
- package/dist/embedded-admin.cjs +135 -7
- package/dist/embedded-admin.cjs.map +1 -1
- package/dist/embedded-admin.d.cts +35 -2
- package/dist/embedded-admin.d.ts +35 -2
- package/dist/embedded-admin.js +135 -7
- package/dist/embedded-admin.js.map +1 -1
- package/dist/errors.cjs +2 -0
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.cts +3 -3
- package/dist/errors.d.ts +3 -3
- package/dist/errors.js +2 -0
- package/dist/errors.js.map +1 -1
- package/dist/{index-DnKgjPGM.d.ts → index-CBaP4q8r.d.ts} +3 -3
- package/dist/{index-CX6si6YC.d.cts → index-CI_LFWiG.d.cts} +3 -3
- package/dist/index.cjs +396 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -9
- package/dist/index.d.ts +24 -9
- package/dist/index.js +396 -26
- package/dist/index.js.map +1 -1
- package/dist/{payload-types-DTAaWKrp.d.cts → payload-types-BRg8Yary.d.cts} +262 -177
- package/dist/{payload-types-DTAaWKrp.d.ts → payload-types-BRg8Yary.d.ts} +262 -177
- package/dist/query.cjs +20 -0
- package/dist/query.cjs.map +1 -1
- package/dist/query.d.cts +5 -5
- package/dist/query.d.ts +5 -5
- package/dist/query.js +20 -0
- package/dist/query.js.map +1 -1
- package/dist/realtime.d.cts +2 -2
- package/dist/realtime.d.ts +2 -2
- package/dist/server.cjs +459 -46
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +10 -8
- package/dist/server.d.ts +10 -8
- package/dist/server.js +459 -46
- package/dist/server.js.map +1 -1
- package/dist/storefront-cache.cjs +2 -0
- package/dist/storefront-cache.cjs.map +1 -1
- package/dist/storefront-cache.js +2 -0
- package/dist/storefront-cache.js.map +1 -1
- package/dist/{types-DdlhpNVv.d.ts → types-Cmnxxvuv.d.ts} +238 -21
- package/dist/{types-Bzgf4mTo.d.cts → types-CnkJQUez.d.cts} +238 -21
- package/dist/{types-DX8Z44yQ.d.ts → types-DLjSqL0P.d.ts} +2 -2
- package/dist/{types-CpSiyJud.d.cts → types-FyklqLAk.d.cts} +2 -2
- package/dist/ui/form.d.cts +1 -1
- package/dist/ui/form.d.ts +1 -1
- package/dist/ui/video.d.cts +1 -1
- package/dist/ui/video.d.ts +1 -1
- package/dist/webhook.d.cts +5 -5
- package/dist/webhook.d.ts +5 -5
- package/package.json +2 -4
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import './payload-types-
|
|
1
|
+
import { dd as DebugConfig, dj as RetryConfig, d6 as ApiQueryOptions, dg as PayloadFindResponse, dh as PayloadMutationResponse, dy as ApiDocumentWriteOptions, dz as ApiWriteOptions, dA as ApiDeleteOptions, dB as PublicReadQueryOptions } from './types-CnkJQUez.cjs';
|
|
2
|
+
import './payload-types-BRg8Yary.cjs';
|
|
3
3
|
import { GenerateMetadataOptions, Metadata } from './metadata.cjs';
|
|
4
|
-
import { C as Collection, S as ServerCollection, P as PublicCollection } from './const-
|
|
5
|
-
import { C as CollectionType } from './types-
|
|
4
|
+
import { C as Collection, S as ServerCollection, P as PublicCollection } from './const-_ZfJjRQG.cjs';
|
|
5
|
+
import { C as CollectionType } from './types-FyklqLAk.cjs';
|
|
6
6
|
|
|
7
7
|
interface FetchOptions extends RequestInit {
|
|
8
8
|
apiUrl?: string;
|
|
@@ -90,21 +90,17 @@ declare class CollectionQueryBuilder<T extends Collection> {
|
|
|
90
90
|
/**
|
|
91
91
|
* Create a new document
|
|
92
92
|
* POST /api/{collection}
|
|
93
|
+
* Pass `locale` to write localized fields in a tenant-enabled locale.
|
|
93
94
|
* @returns Payload CMS mutation response with doc and message
|
|
94
95
|
*/
|
|
95
|
-
create(data: Partial<CollectionType<T>>, options?:
|
|
96
|
-
file?: File | Blob;
|
|
97
|
-
filename?: string;
|
|
98
|
-
}): Promise<PayloadMutationResponse<CollectionType<T>>>;
|
|
96
|
+
create(data: Partial<CollectionType<T>>, options?: ApiDocumentWriteOptions): Promise<PayloadMutationResponse<CollectionType<T>>>;
|
|
99
97
|
/**
|
|
100
98
|
* Update a document by ID
|
|
101
99
|
* PATCH /api/{collection}/{id}
|
|
100
|
+
* Pass `locale` to write localized fields in a tenant-enabled locale.
|
|
102
101
|
* @returns Payload CMS mutation response with doc and message
|
|
103
102
|
*/
|
|
104
|
-
update(id: string, data: Partial<CollectionType<T>>, options?:
|
|
105
|
-
file?: File | Blob;
|
|
106
|
-
filename?: string;
|
|
107
|
-
}): Promise<PayloadMutationResponse<CollectionType<T>>>;
|
|
103
|
+
update(id: string, data: Partial<CollectionType<T>>, options?: ApiDocumentWriteOptions): Promise<PayloadMutationResponse<CollectionType<T>>>;
|
|
108
104
|
/**
|
|
109
105
|
* Count documents
|
|
110
106
|
* GET /api/{collection}/count
|
|
@@ -130,7 +126,7 @@ declare class CollectionQueryBuilder<T extends Collection> {
|
|
|
130
126
|
* PATCH /api/{collection}
|
|
131
127
|
* @returns Payload CMS find response with updated docs
|
|
132
128
|
*/
|
|
133
|
-
updateMany(where: ApiQueryOptions['where'], data: Partial<CollectionType<T
|
|
129
|
+
updateMany(where: ApiQueryOptions['where'], data: Partial<CollectionType<T>>, options?: ApiWriteOptions): Promise<PayloadFindResponse<CollectionType<T>>>;
|
|
134
130
|
/**
|
|
135
131
|
* Delete a document by ID
|
|
136
132
|
* DELETE /api/{collection}/{id}
|
|
@@ -172,12 +168,12 @@ declare class CollectionClient<TCollection extends Collection = PublicCollection
|
|
|
172
168
|
* Create document
|
|
173
169
|
* POST /api/{collection}
|
|
174
170
|
*/
|
|
175
|
-
requestCreate<T = unknown>(endpoint: string, data?: unknown): Promise<PayloadMutationResponse<T>>;
|
|
171
|
+
requestCreate<T = unknown>(endpoint: string, data?: unknown, options?: ApiWriteOptions): Promise<PayloadMutationResponse<T>>;
|
|
176
172
|
/**
|
|
177
173
|
* Update document
|
|
178
174
|
* PATCH /api/{collection}/{id}
|
|
179
175
|
*/
|
|
180
|
-
requestUpdate<T = unknown>(endpoint: string, data?: unknown): Promise<PayloadMutationResponse<T>>;
|
|
176
|
+
requestUpdate<T = unknown>(endpoint: string, data?: unknown, options?: ApiWriteOptions): Promise<PayloadMutationResponse<T>>;
|
|
181
177
|
/**
|
|
182
178
|
* Count documents
|
|
183
179
|
* GET /api/{collection}/count
|
|
@@ -192,7 +188,7 @@ declare class CollectionClient<TCollection extends Collection = PublicCollection
|
|
|
192
188
|
requestUpdateMany<T = unknown>(endpoint: string, data: {
|
|
193
189
|
where?: ApiQueryOptions['where'];
|
|
194
190
|
data: unknown;
|
|
195
|
-
}): Promise<PayloadFindResponse<T>>;
|
|
191
|
+
}, options?: ApiWriteOptions): Promise<PayloadFindResponse<T>>;
|
|
196
192
|
/**
|
|
197
193
|
* Delete document
|
|
198
194
|
* DELETE /api/{collection}/{id}
|
|
@@ -209,12 +205,12 @@ declare class CollectionClient<TCollection extends Collection = PublicCollection
|
|
|
209
205
|
* Create document with file upload
|
|
210
206
|
* POST /api/{collection} (multipart/form-data)
|
|
211
207
|
*/
|
|
212
|
-
requestCreateWithFile<T = unknown>(endpoint: string, data: unknown, file: File | Blob, filename?: string): Promise<PayloadMutationResponse<T>>;
|
|
208
|
+
requestCreateWithFile<T = unknown>(endpoint: string, data: unknown, file: File | Blob, filename?: string, options?: ApiWriteOptions): Promise<PayloadMutationResponse<T>>;
|
|
213
209
|
/**
|
|
214
210
|
* Update document with file upload
|
|
215
211
|
* PATCH /api/{collection}/{id} (multipart/form-data)
|
|
216
212
|
*/
|
|
217
|
-
requestUpdateWithFile<T = unknown>(endpoint: string, data: unknown, file: File | Blob, filename?: string): Promise<PayloadMutationResponse<T>>;
|
|
213
|
+
requestUpdateWithFile<T = unknown>(endpoint: string, data: unknown, file: File | Blob, filename?: string, options?: ApiWriteOptions): Promise<PayloadMutationResponse<T>>;
|
|
218
214
|
}
|
|
219
215
|
declare class ServerCollectionClient extends CollectionClient<ServerCollection> {
|
|
220
216
|
from<T extends ServerCollection>(collection: T): ServerCollectionQueryBuilder<T>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import './payload-types-
|
|
1
|
+
import { dd as DebugConfig, dj as RetryConfig, d6 as ApiQueryOptions, dg as PayloadFindResponse, dh as PayloadMutationResponse, dy as ApiDocumentWriteOptions, dz as ApiWriteOptions, dA as ApiDeleteOptions, dB as PublicReadQueryOptions } from './types-Cmnxxvuv.js';
|
|
2
|
+
import './payload-types-BRg8Yary.js';
|
|
3
3
|
import { GenerateMetadataOptions, Metadata } from './metadata.js';
|
|
4
|
-
import { C as Collection, S as ServerCollection, P as PublicCollection } from './const-
|
|
5
|
-
import { C as CollectionType } from './types-
|
|
4
|
+
import { C as Collection, S as ServerCollection, P as PublicCollection } from './const-BJBK7jBl.js';
|
|
5
|
+
import { C as CollectionType } from './types-DLjSqL0P.js';
|
|
6
6
|
|
|
7
7
|
interface FetchOptions extends RequestInit {
|
|
8
8
|
apiUrl?: string;
|
|
@@ -90,21 +90,17 @@ declare class CollectionQueryBuilder<T extends Collection> {
|
|
|
90
90
|
/**
|
|
91
91
|
* Create a new document
|
|
92
92
|
* POST /api/{collection}
|
|
93
|
+
* Pass `locale` to write localized fields in a tenant-enabled locale.
|
|
93
94
|
* @returns Payload CMS mutation response with doc and message
|
|
94
95
|
*/
|
|
95
|
-
create(data: Partial<CollectionType<T>>, options?:
|
|
96
|
-
file?: File | Blob;
|
|
97
|
-
filename?: string;
|
|
98
|
-
}): Promise<PayloadMutationResponse<CollectionType<T>>>;
|
|
96
|
+
create(data: Partial<CollectionType<T>>, options?: ApiDocumentWriteOptions): Promise<PayloadMutationResponse<CollectionType<T>>>;
|
|
99
97
|
/**
|
|
100
98
|
* Update a document by ID
|
|
101
99
|
* PATCH /api/{collection}/{id}
|
|
100
|
+
* Pass `locale` to write localized fields in a tenant-enabled locale.
|
|
102
101
|
* @returns Payload CMS mutation response with doc and message
|
|
103
102
|
*/
|
|
104
|
-
update(id: string, data: Partial<CollectionType<T>>, options?:
|
|
105
|
-
file?: File | Blob;
|
|
106
|
-
filename?: string;
|
|
107
|
-
}): Promise<PayloadMutationResponse<CollectionType<T>>>;
|
|
103
|
+
update(id: string, data: Partial<CollectionType<T>>, options?: ApiDocumentWriteOptions): Promise<PayloadMutationResponse<CollectionType<T>>>;
|
|
108
104
|
/**
|
|
109
105
|
* Count documents
|
|
110
106
|
* GET /api/{collection}/count
|
|
@@ -130,7 +126,7 @@ declare class CollectionQueryBuilder<T extends Collection> {
|
|
|
130
126
|
* PATCH /api/{collection}
|
|
131
127
|
* @returns Payload CMS find response with updated docs
|
|
132
128
|
*/
|
|
133
|
-
updateMany(where: ApiQueryOptions['where'], data: Partial<CollectionType<T
|
|
129
|
+
updateMany(where: ApiQueryOptions['where'], data: Partial<CollectionType<T>>, options?: ApiWriteOptions): Promise<PayloadFindResponse<CollectionType<T>>>;
|
|
134
130
|
/**
|
|
135
131
|
* Delete a document by ID
|
|
136
132
|
* DELETE /api/{collection}/{id}
|
|
@@ -172,12 +168,12 @@ declare class CollectionClient<TCollection extends Collection = PublicCollection
|
|
|
172
168
|
* Create document
|
|
173
169
|
* POST /api/{collection}
|
|
174
170
|
*/
|
|
175
|
-
requestCreate<T = unknown>(endpoint: string, data?: unknown): Promise<PayloadMutationResponse<T>>;
|
|
171
|
+
requestCreate<T = unknown>(endpoint: string, data?: unknown, options?: ApiWriteOptions): Promise<PayloadMutationResponse<T>>;
|
|
176
172
|
/**
|
|
177
173
|
* Update document
|
|
178
174
|
* PATCH /api/{collection}/{id}
|
|
179
175
|
*/
|
|
180
|
-
requestUpdate<T = unknown>(endpoint: string, data?: unknown): Promise<PayloadMutationResponse<T>>;
|
|
176
|
+
requestUpdate<T = unknown>(endpoint: string, data?: unknown, options?: ApiWriteOptions): Promise<PayloadMutationResponse<T>>;
|
|
181
177
|
/**
|
|
182
178
|
* Count documents
|
|
183
179
|
* GET /api/{collection}/count
|
|
@@ -192,7 +188,7 @@ declare class CollectionClient<TCollection extends Collection = PublicCollection
|
|
|
192
188
|
requestUpdateMany<T = unknown>(endpoint: string, data: {
|
|
193
189
|
where?: ApiQueryOptions['where'];
|
|
194
190
|
data: unknown;
|
|
195
|
-
}): Promise<PayloadFindResponse<T>>;
|
|
191
|
+
}, options?: ApiWriteOptions): Promise<PayloadFindResponse<T>>;
|
|
196
192
|
/**
|
|
197
193
|
* Delete document
|
|
198
194
|
* DELETE /api/{collection}/{id}
|
|
@@ -209,12 +205,12 @@ declare class CollectionClient<TCollection extends Collection = PublicCollection
|
|
|
209
205
|
* Create document with file upload
|
|
210
206
|
* POST /api/{collection} (multipart/form-data)
|
|
211
207
|
*/
|
|
212
|
-
requestCreateWithFile<T = unknown>(endpoint: string, data: unknown, file: File | Blob, filename?: string): Promise<PayloadMutationResponse<T>>;
|
|
208
|
+
requestCreateWithFile<T = unknown>(endpoint: string, data: unknown, file: File | Blob, filename?: string, options?: ApiWriteOptions): Promise<PayloadMutationResponse<T>>;
|
|
213
209
|
/**
|
|
214
210
|
* Update document with file upload
|
|
215
211
|
* PATCH /api/{collection}/{id} (multipart/form-data)
|
|
216
212
|
*/
|
|
217
|
-
requestUpdateWithFile<T = unknown>(endpoint: string, data: unknown, file: File | Blob, filename?: string): Promise<PayloadMutationResponse<T>>;
|
|
213
|
+
requestUpdateWithFile<T = unknown>(endpoint: string, data: unknown, file: File | Blob, filename?: string, options?: ApiWriteOptions): Promise<PayloadMutationResponse<T>>;
|
|
218
214
|
}
|
|
219
215
|
declare class ServerCollectionClient extends CollectionClient<ServerCollection> {
|
|
220
216
|
from<T extends ServerCollection>(collection: T): ServerCollectionQueryBuilder<T>;
|
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var server_exports = {};
|
|
22
22
|
__export(server_exports, {
|
|
23
23
|
fetchEmbeddedAdminJwks: () => fetchEmbeddedAdminJwks,
|
|
24
|
+
verifyEmbeddedAdminExecution: () => verifyEmbeddedAdminExecution,
|
|
24
25
|
verifyEmbeddedAdminSession: () => verifyEmbeddedAdminSession
|
|
25
26
|
});
|
|
26
27
|
module.exports = __toCommonJS(server_exports);
|
|
@@ -113,6 +114,7 @@ var COMMERCE_ERROR_CODES = [
|
|
|
113
114
|
"cart_not_active",
|
|
114
115
|
"cart_locked",
|
|
115
116
|
"cart_empty",
|
|
117
|
+
"shipping_address_required",
|
|
116
118
|
"cart_market_unavailable",
|
|
117
119
|
"cart_market_mismatch",
|
|
118
120
|
"checkout_not_open",
|
|
@@ -129,6 +131,7 @@ var COMMERCE_ERROR_CODES = [
|
|
|
129
131
|
"price_changed",
|
|
130
132
|
"pricing_fact_in_use",
|
|
131
133
|
"insufficient_stock",
|
|
134
|
+
"credit_insufficient",
|
|
132
135
|
"reservation_conflict",
|
|
133
136
|
"stock_lock_unavailable",
|
|
134
137
|
"variant_not_found",
|
|
@@ -207,9 +210,56 @@ var ValidationError = class extends SDKError {
|
|
|
207
210
|
};
|
|
208
211
|
var createValidationError = (message, details, userMessage, suggestion, status) => new ValidationError(message, details, userMessage, suggestion, status);
|
|
209
212
|
|
|
213
|
+
// src/embedded-admin/actions.ts
|
|
214
|
+
var EMBEDDED_ADMIN_EXECUTION_AUDIENCE_PREFIX = "urn:01-software:embedded-admin-execution:";
|
|
215
|
+
var EMBEDDED_ADMIN_MAX_SELECTED_IDS = 100;
|
|
216
|
+
var ACTION_ID = /^[a-z][a-z0-9_-]{0,63}$/;
|
|
217
|
+
var COLLECTION = /^[a-z][a-z0-9-]{0,63}$/;
|
|
218
|
+
var EXECUTION_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
219
|
+
function recordWithKeys(value, keys) {
|
|
220
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
221
|
+
throw createValidationError("Invalid embedded admin action context.");
|
|
222
|
+
}
|
|
223
|
+
const record = value;
|
|
224
|
+
if (Object.keys(record).some((key) => !keys.includes(key))) {
|
|
225
|
+
throw createValidationError("Invalid embedded admin action context.");
|
|
226
|
+
}
|
|
227
|
+
return record;
|
|
228
|
+
}
|
|
229
|
+
function normalizeEmbeddedAdminExecutionContext(value) {
|
|
230
|
+
const input = recordWithKeys(value, [
|
|
231
|
+
"executionId",
|
|
232
|
+
"expiresAt",
|
|
233
|
+
"actionId",
|
|
234
|
+
"collection",
|
|
235
|
+
"selectedIds"
|
|
236
|
+
]);
|
|
237
|
+
if (typeof input.executionId !== "string" || !EXECUTION_ID.test(input.executionId) || typeof input.expiresAt !== "number" || !Number.isSafeInteger(input.expiresAt) || input.expiresAt <= 0 || typeof input.actionId !== "string" || !ACTION_ID.test(input.actionId) || typeof input.collection !== "string" || !COLLECTION.test(input.collection) || !Array.isArray(input.selectedIds) || input.selectedIds.length > EMBEDDED_ADMIN_MAX_SELECTED_IDS || input.selectedIds.some(
|
|
238
|
+
(id) => typeof id !== "string" || !id || id.length > 128 || id.trim() !== id || Array.from(id).some(
|
|
239
|
+
(character) => character.charCodeAt(0) <= 32 || character.charCodeAt(0) === 127
|
|
240
|
+
)
|
|
241
|
+
) || new Set(input.selectedIds).size !== input.selectedIds.length)
|
|
242
|
+
throw createValidationError("Invalid embedded admin execution context.");
|
|
243
|
+
return {
|
|
244
|
+
executionId: input.executionId,
|
|
245
|
+
expiresAt: input.expiresAt,
|
|
246
|
+
actionId: input.actionId,
|
|
247
|
+
collection: input.collection,
|
|
248
|
+
selectedIds: [...input.selectedIds].sort()
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
function embeddedAdminExecutionContextsEqual(left, right) {
|
|
252
|
+
try {
|
|
253
|
+
return JSON.stringify(normalizeEmbeddedAdminExecutionContext(left)) === JSON.stringify(normalizeEmbeddedAdminExecutionContext(right));
|
|
254
|
+
} catch {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
210
259
|
// src/embedded-admin/index.ts
|
|
211
260
|
var EMBEDDED_ADMIN_SESSION_TTL_SECONDS = 60;
|
|
212
261
|
var EMBEDDED_ADMIN_APP_KEY = "primary";
|
|
262
|
+
var MAX_PATH_LENGTH = 512;
|
|
213
263
|
var EMBEDDED_ADMIN_TENANT_ROLES = [
|
|
214
264
|
"tenant-admin",
|
|
215
265
|
"tenant-editor",
|
|
@@ -236,6 +286,23 @@ function normalizeEmbeddedAdminExactOrigin(value, options = {}) {
|
|
|
236
286
|
if (parsed.pathname !== "/" || trimmed.endsWith("/")) return null;
|
|
237
287
|
return parsed.origin;
|
|
238
288
|
}
|
|
289
|
+
function normalizeEmbeddedAdminRelativePath(value) {
|
|
290
|
+
if (typeof value !== "string") return null;
|
|
291
|
+
const trimmed = value.trim();
|
|
292
|
+
if (!trimmed.startsWith("/") || trimmed.startsWith("//") || trimmed.length > MAX_PATH_LENGTH) {
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
let parsed;
|
|
296
|
+
try {
|
|
297
|
+
parsed = new URL(trimmed, "https://embedded.invalid");
|
|
298
|
+
} catch {
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
if (parsed.origin !== "https://embedded.invalid" || parsed.pathname.startsWith("//") || parsed.search || parsed.hash || parsed.username || parsed.password) {
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
return parsed.pathname;
|
|
305
|
+
}
|
|
239
306
|
|
|
240
307
|
// src/embedded-admin/server.ts
|
|
241
308
|
var ALGORITHMS = ["RS256", "ES256"];
|
|
@@ -279,6 +346,53 @@ async function fetchEmbeddedAdminJwks(consoleOrigin, options = {}) {
|
|
|
279
346
|
return parseJwks(JSON.parse(text));
|
|
280
347
|
}
|
|
281
348
|
async function verifyEmbeddedAdminSession(options) {
|
|
349
|
+
const claims = await verifySession(options);
|
|
350
|
+
if ("protocol_version" in claims || "execution_context" in claims || "token_use" in claims) {
|
|
351
|
+
throw new Error("An action assertion requires execution verification.");
|
|
352
|
+
}
|
|
353
|
+
return claims;
|
|
354
|
+
}
|
|
355
|
+
async function verifyEmbeddedAdminExecution(options) {
|
|
356
|
+
if (typeof options.consumeExecution !== "function") {
|
|
357
|
+
throw createValidationError("A durable execution consumer is required.");
|
|
358
|
+
}
|
|
359
|
+
const clock = options.clock ?? (() => Math.floor(Date.now() / 1e3));
|
|
360
|
+
const currentSecond = () => {
|
|
361
|
+
const now = clock();
|
|
362
|
+
if (!Number.isSafeInteger(now) || now < 0)
|
|
363
|
+
throw createValidationError("A trusted Unix-second clock is required.");
|
|
364
|
+
return now;
|
|
365
|
+
};
|
|
366
|
+
const claims = await verifySession({ ...options, now: currentSecond() }, true);
|
|
367
|
+
const execution = normalizeEmbeddedAdminExecutionContext(
|
|
368
|
+
claims.execution_context
|
|
369
|
+
);
|
|
370
|
+
const frame = new URL(options.frameUrl);
|
|
371
|
+
const path = normalizeEmbeddedAdminRelativePath(frame.pathname);
|
|
372
|
+
if (claims.protocol_version !== 2 || !["super-admin", "tenant-admin"].includes(claims.tenant_role) || "token_use" in claims || !path || frame.origin !== claims.dest || `${frame.origin}${path}` !== options.frameUrl || claims.frame_url !== options.frameUrl || claims.exp !== execution.expiresAt || currentSecond() >= execution.expiresAt || !embeddedAdminExecutionContextsEqual(execution, options.execution))
|
|
373
|
+
throw new Error(
|
|
374
|
+
"Embedded admin execution context does not match its assertion."
|
|
375
|
+
);
|
|
376
|
+
const consumed = await options.consumeExecution({
|
|
377
|
+
issuer: claims.iss,
|
|
378
|
+
tenantId: claims.tenant_id,
|
|
379
|
+
operatorId: claims.operator_id,
|
|
380
|
+
appKey: claims.app_key,
|
|
381
|
+
executionId: execution.executionId,
|
|
382
|
+
expiresAt: execution.expiresAt
|
|
383
|
+
});
|
|
384
|
+
if (consumed !== true)
|
|
385
|
+
throw new Error("Embedded admin execution was already consumed.");
|
|
386
|
+
if (currentSecond() >= execution.expiresAt)
|
|
387
|
+
throw new Error("Embedded admin execution expired during consumption.");
|
|
388
|
+
return {
|
|
389
|
+
...claims,
|
|
390
|
+
protocol_version: 2,
|
|
391
|
+
frame_url: options.frameUrl,
|
|
392
|
+
execution_context: execution
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
async function verifySession(options, executionPurpose = false) {
|
|
282
396
|
const allowedRoles = options.allowedRoles ?? ["super-admin", "tenant-admin"];
|
|
283
397
|
if (!Array.isArray(allowedRoles) || allowedRoles.some(
|
|
284
398
|
(role) => !["super-admin", ...EMBEDDED_ADMIN_TENANT_ROLES].includes(role)
|
|
@@ -298,6 +412,7 @@ async function verifyEmbeddedAdminSession(options) {
|
|
|
298
412
|
"consoleOrigin and destination must be exact origins."
|
|
299
413
|
);
|
|
300
414
|
}
|
|
415
|
+
const audience = executionPurpose ? `${EMBEDDED_ADMIN_EXECUTION_AUDIENCE_PREFIX}${destination}` : destination;
|
|
301
416
|
if (typeof options.channelId !== "string" || options.channelId.length < 16 || options.channelId.length > 128 || typeof options.token !== "string" || options.token.length === 0) {
|
|
302
417
|
throw createValidationError("Embedded admin session input is invalid.");
|
|
303
418
|
}
|
|
@@ -311,7 +426,7 @@ async function verifyEmbeddedAdminSession(options) {
|
|
|
311
426
|
(0, import_jose.createLocalJWKSet)(jwks),
|
|
312
427
|
{
|
|
313
428
|
algorithms: [...ALGORITHMS],
|
|
314
|
-
audience
|
|
429
|
+
audience,
|
|
315
430
|
clockTolerance: 0,
|
|
316
431
|
currentDate: new Date(currentSecond * 1e3),
|
|
317
432
|
issuer,
|
|
@@ -319,7 +434,7 @@ async function verifyEmbeddedAdminSession(options) {
|
|
|
319
434
|
}
|
|
320
435
|
);
|
|
321
436
|
const lifetime = typeof payload.exp === "number" && typeof payload.iat === "number" ? payload.exp - payload.iat : Number.POSITIVE_INFINITY;
|
|
322
|
-
if (typeof protectedHeader.kid !== "string" || protectedHeader.kid.length === 0 || !Number.isInteger(payload.iat) || !Number.isInteger(payload.nbf) || !Number.isInteger(payload.exp) || payload.iat > currentSecond || lifetime <= 0 || lifetime > EMBEDDED_ADMIN_SESSION_TTL_SECONDS || payload.nbf !== payload.iat || payload.aud !==
|
|
437
|
+
if (typeof protectedHeader.kid !== "string" || protectedHeader.kid.length === 0 || !Number.isInteger(payload.iat) || !Number.isInteger(payload.nbf) || !Number.isInteger(payload.exp) || payload.iat > currentSecond || lifetime <= 0 || lifetime > EMBEDDED_ADMIN_SESSION_TTL_SECONDS || payload.nbf !== payload.iat || payload.aud !== audience || typeof payload.jti !== "string" || payload.jti.length === 0 || payload.app_key !== EMBEDDED_ADMIN_APP_KEY || payload.channel_id !== options.channelId || payload.dest !== destination || typeof payload.operator_id !== "string" || payload.operator_id.length === 0 || payload.sub !== payload.operator_id || typeof payload.tenant_id !== "string" || payload.tenant_id.length === 0 || !["super-admin", ...EMBEDDED_ADMIN_TENANT_ROLES].includes(
|
|
323
438
|
payload.tenant_role
|
|
324
439
|
) || !allowedRoles.includes(payload.tenant_role)) {
|
|
325
440
|
throw new Error("Embedded admin session claims are invalid.");
|