@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 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/embedded-admin/index.ts","../src/core/errors.ts"],"sourcesContent":["import { createValidationError } from '../core/internal/errors'\n\nexport const EMBEDDED_ADMIN_PROTOCOL_VERSION = 1 as const\nexport const EMBEDDED_ADMIN_CHALLENGE_MESSAGE =\n '01.embedded-admin.challenge' as const\nexport const EMBEDDED_ADMIN_READY_MESSAGE = '01.embedded-admin.ready' as const\nexport const EMBEDDED_ADMIN_SESSION_MESSAGE =\n '01.embedded-admin.session' as const\nexport const EMBEDDED_ADMIN_SESSION_TTL_SECONDS = 60 as const\nexport const EMBEDDED_ADMIN_APP_KEY = 'primary' as const\n\nconst DEFAULT_RECEIVER_TIMEOUT_MS = 35_000\nconst MAX_RECEIVER_TIMEOUT_MS = 120_000\nconst MAX_LABEL_LENGTH = 80\nconst MAX_PATH_LENGTH = 512\n\nexport type EmbeddedAdminChallengeMessage = {\n type: typeof EMBEDDED_ADMIN_CHALLENGE_MESSAGE\n version: typeof EMBEDDED_ADMIN_PROTOCOL_VERSION\n requestId: string\n}\n\nexport type EmbeddedAdminReadyMessage = {\n type: typeof EMBEDDED_ADMIN_READY_MESSAGE\n version: typeof EMBEDDED_ADMIN_PROTOCOL_VERSION\n requestId: string\n}\n\nexport type EmbeddedAdminSessionMessage = {\n type: typeof EMBEDDED_ADMIN_SESSION_MESSAGE\n version: typeof EMBEDDED_ADMIN_PROTOCOL_VERSION\n requestId: string\n token: string\n}\n\n/** Exact execution roles; this list grants no platform data permissions. */\nexport const EMBEDDED_ADMIN_TENANT_ROLES = [\n 'tenant-admin',\n 'tenant-editor',\n 'tenant-viewer',\n] as const\nexport type EmbeddedAdminTenantRole =\n (typeof EMBEDDED_ADMIN_TENANT_ROLES)[number]\n\n/** Missing legacy settings retain administrator-only execution; invalid settings fail closed. */\nexport function normalizeEmbeddedAdminAllowedRoles(\n value: unknown,\n): EmbeddedAdminTenantRole[] | null {\n if (value === undefined || value === null) return ['tenant-admin']\n if (\n !Array.isArray(value) ||\n value.some((role) => !EMBEDDED_ADMIN_TENANT_ROLES.includes(role))\n )\n return null\n return EMBEDDED_ADMIN_TENANT_ROLES.filter((role) => value.includes(role))\n}\n\nexport type EmbeddedAdminBindingConfiguration = {\n allowedRoles?: EmbeddedAdminTenantRole[]\n enabled: boolean\n label: string\n origin: string\n path: string\n}\n\nexport type EmbeddedAdminSessionReceipt = {\n requestId: string\n token: string\n}\n\nexport type ReceiveEmbeddedAdminSessionOptions = {\n /** Test fixtures only. Production integrations must keep HTTPS enforcement. */\n allowLoopbackHttp?: boolean\n /** Exact Console origin configured by the receiver deployment. */\n consoleOrigin: string\n /** Cancels the one-shot receiver and closes every transferred port. */\n signal?: AbortSignal\n /** Defaults to 35 seconds and is capped at 120 seconds. */\n timeoutMs?: number\n}\n\nfunction isLoopbackHostname(hostname: string): boolean {\n return (\n hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '[::1]'\n )\n}\n\nexport function normalizeEmbeddedAdminExactOrigin(\n value: unknown,\n options: { allowLoopbackHttp?: boolean } = {},\n): string | null {\n if (typeof value !== 'string') return null\n const trimmed = value.trim()\n if (!trimmed || trimmed.length > 2048) return null\n\n let parsed: URL\n try {\n parsed = new URL(trimmed)\n } catch {\n return null\n }\n\n const allowedProtocol =\n parsed.protocol === 'https:' ||\n (options.allowLoopbackHttp === true &&\n parsed.protocol === 'http:' &&\n isLoopbackHostname(parsed.hostname))\n if (!allowedProtocol || parsed.hostname.includes('*')) return null\n if (parsed.username || parsed.password || parsed.search || parsed.hash) {\n return null\n }\n if (parsed.pathname !== '/' || trimmed.endsWith('/')) return null\n\n return parsed.origin\n}\n\nexport function normalizeEmbeddedAdminRelativePath(\n value: unknown,\n): string | null {\n if (typeof value !== 'string') return null\n const trimmed = value.trim()\n if (\n !trimmed.startsWith('/') ||\n trimmed.startsWith('//') ||\n trimmed.length > MAX_PATH_LENGTH\n ) {\n return null\n }\n\n let parsed: URL\n try {\n parsed = new URL(trimmed, 'https://embedded.invalid')\n } catch {\n return null\n }\n\n if (\n parsed.origin !== 'https://embedded.invalid' ||\n parsed.pathname.startsWith('//') ||\n parsed.search ||\n parsed.hash ||\n parsed.username ||\n parsed.password\n ) {\n return null\n }\n\n return parsed.pathname\n}\n\nexport function normalizeEmbeddedAdminBindingConfiguration(\n value: unknown,\n options: {\n allowLoopbackConsoleHttp?: boolean\n consoleOrigin?: string\n } = {},\n): EmbeddedAdminBindingConfiguration {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw createValidationError('Embedded admin binding must be an object.')\n }\n\n const input = value as Record<string, unknown>\n const allowedRoles = normalizeEmbeddedAdminAllowedRoles(input.allowedRoles)\n if (!allowedRoles)\n throw createValidationError(\n 'Embedded admin allowedRoles must contain only tenant execution roles.',\n )\n const label = typeof input.label === 'string' ? input.label.trim() : ''\n const origin = normalizeEmbeddedAdminExactOrigin(input.origin)\n const path = normalizeEmbeddedAdminRelativePath(input.path)\n const consoleOrigin = options.consoleOrigin\n ? normalizeEmbeddedAdminExactOrigin(options.consoleOrigin, {\n allowLoopbackHttp: options.allowLoopbackConsoleHttp === true,\n })\n : null\n\n if (!label || label.length > MAX_LABEL_LENGTH) {\n throw createValidationError(\n `Embedded admin label must be between 1 and ${MAX_LABEL_LENGTH} characters.`,\n )\n }\n if (!origin) {\n throw createValidationError(\n 'Embedded admin origin must be an exact HTTPS origin without a path, query, fragment, wildcard, or credentials.',\n )\n }\n if (!path) {\n throw createValidationError(\n 'Embedded admin path must begin with / and must not include a query or fragment.',\n )\n }\n if (consoleOrigin && origin === consoleOrigin) {\n throw createValidationError(\n 'Embedded admin origin must be different from the Console origin.',\n )\n }\n\n return {\n allowedRoles,\n enabled: input.enabled !== false,\n label,\n origin,\n path,\n }\n}\n\nexport function isEmbeddedAdminChallengeMessage(\n value: unknown,\n): value is EmbeddedAdminChallengeMessage {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false\n const message = value as Record<string, unknown>\n return (\n message.type === EMBEDDED_ADMIN_CHALLENGE_MESSAGE &&\n message.version === EMBEDDED_ADMIN_PROTOCOL_VERSION &&\n typeof message.requestId === 'string' &&\n message.requestId.length >= 16 &&\n message.requestId.length <= 128\n )\n}\n\nexport function isEmbeddedAdminReadyMessage(\n value: unknown,\n): value is EmbeddedAdminReadyMessage {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false\n const message = value as Record<string, unknown>\n return (\n message.type === EMBEDDED_ADMIN_READY_MESSAGE &&\n message.version === EMBEDDED_ADMIN_PROTOCOL_VERSION &&\n typeof message.requestId === 'string' &&\n message.requestId.length >= 16 &&\n message.requestId.length <= 128\n )\n}\n\nexport function isEmbeddedAdminSessionMessage(\n value: unknown,\n): value is EmbeddedAdminSessionMessage {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false\n const message = value as Record<string, unknown>\n return (\n message.type === EMBEDDED_ADMIN_SESSION_MESSAGE &&\n message.version === EMBEDDED_ADMIN_PROTOCOL_VERSION &&\n typeof message.requestId === 'string' &&\n message.requestId.length >= 16 &&\n message.requestId.length <= 128 &&\n typeof message.token === 'string' &&\n message.token.length > 0\n )\n}\n\n/**\n * Receives one Console assertion through the exact parent/origin challenge\n * channel. Forward the returned token immediately to the receiver backend;\n * never persist, log, decode, or use it as Console API authority in-browser.\n */\nexport function receiveEmbeddedAdminSession(\n options: ReceiveEmbeddedAdminSessionOptions,\n): Promise<EmbeddedAdminSessionReceipt> {\n if (typeof window === 'undefined' || window.parent === window) {\n return Promise.reject(\n createValidationError(\n 'receiveEmbeddedAdminSession must run inside an embedded browser frame.',\n ),\n )\n }\n\n const consoleOrigin = normalizeEmbeddedAdminExactOrigin(\n options.consoleOrigin,\n { allowLoopbackHttp: options.allowLoopbackHttp === true },\n )\n if (!consoleOrigin) {\n return Promise.reject(\n createValidationError('consoleOrigin must be one exact HTTPS origin.'),\n )\n }\n\n const timeoutMs = options.timeoutMs ?? DEFAULT_RECEIVER_TIMEOUT_MS\n if (\n !Number.isInteger(timeoutMs) ||\n timeoutMs <= 0 ||\n timeoutMs > MAX_RECEIVER_TIMEOUT_MS\n ) {\n return Promise.reject(\n createValidationError(\n `timeoutMs must be an integer between 1 and ${MAX_RECEIVER_TIMEOUT_MS}.`,\n ),\n )\n }\n\n return new Promise((resolve, reject) => {\n const ports = new Set<MessagePort>()\n let settled = false\n\n const closePorts = () => {\n for (const port of ports) port.close()\n ports.clear()\n }\n const cleanup = () => {\n window.removeEventListener('message', acceptChallenge)\n options.signal?.removeEventListener('abort', abort)\n clearTimeout(timer)\n closePorts()\n }\n const finish = (receipt: EmbeddedAdminSessionReceipt) => {\n if (settled) return\n settled = true\n cleanup()\n resolve(receipt)\n }\n const fail = (error: Error) => {\n if (settled) return\n settled = true\n cleanup()\n reject(error)\n }\n const abort = () =>\n fail(new Error('Embedded admin session receipt aborted.'))\n const acceptSession = (\n event: MessageEvent<unknown>,\n expectedRequestId: string,\n ) => {\n if (\n !isEmbeddedAdminSessionMessage(event.data) ||\n event.data.requestId !== expectedRequestId\n ) {\n return\n }\n finish({ requestId: event.data.requestId, token: event.data.token })\n }\n const acceptChallenge = (event: MessageEvent<unknown>) => {\n if (\n event.source !== window.parent ||\n event.origin !== consoleOrigin ||\n !isEmbeddedAdminChallengeMessage(event.data) ||\n event.ports.length !== 1\n ) {\n for (const port of event.ports) port.close()\n return\n }\n\n const port = event.ports[0]!\n const requestId = event.data.requestId\n ports.add(port)\n port.addEventListener('message', (message) => {\n acceptSession(message, requestId)\n })\n port.start()\n port.postMessage({\n type: EMBEDDED_ADMIN_READY_MESSAGE,\n version: EMBEDDED_ADMIN_PROTOCOL_VERSION,\n requestId,\n } satisfies EmbeddedAdminReadyMessage)\n }\n\n const timer = setTimeout(() => {\n fail(new Error('Timed out waiting for an embedded admin session.'))\n }, timeoutMs)\n\n if (options.signal?.aborted) {\n abort()\n return\n }\n options.signal?.addEventListener('abort', abort, { once: true })\n window.addEventListener('message', acceptChallenge)\n })\n}\n","const SDK_ERROR_BRAND = Symbol.for('@01.software/sdk/SDKError')\nconst SDK_ERROR_TYPE_BRAND = Symbol.for('@01.software/sdk/SDKError.type')\n\ntype SDKErrorType =\n | 'NetworkError'\n | 'ValidationError'\n | 'ApiError'\n | 'ConfigError'\n | 'TimeoutError'\n | 'GoneError'\n | 'ServiceUnavailableError'\n | 'UsageLimitError'\n | 'AuthError'\n | 'PermissionError'\n | 'NotFoundError'\n | 'ConflictError'\n | 'RateLimitError'\n\nfunction defineSDKErrorBrand(error: SDKError): void {\n Object.defineProperty(error, SDK_ERROR_BRAND, {\n value: true,\n enumerable: false,\n configurable: false,\n writable: false,\n })\n}\n\nfunction defineSDKErrorType(error: SDKError, type: SDKErrorType): void {\n Object.defineProperty(error, SDK_ERROR_TYPE_BRAND, {\n value: type,\n enumerable: false,\n configurable: false,\n writable: false,\n })\n}\n\nexport class SDKError extends Error {\n readonly code: string\n readonly status?: number\n readonly details?: unknown\n readonly userMessage?: string\n readonly suggestion?: string\n readonly requestId?: string\n readonly kind?: 'commerce'\n readonly reason?: CommerceErrorCode | 'unknown_commerce_error'\n readonly rawReason?: string\n /** Machine-readable reason from a non-commerce API response. */\n readonly apiReason?: string\n readonly retryable?: boolean\n readonly retryAfter?: number\n\n constructor(\n code: string,\n message: string,\n status?: number,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n ) {\n super(message)\n this.name = 'SDKError'\n this.code = code\n this.status = status\n this.details = details\n this.userMessage = userMessage\n this.suggestion = suggestion\n this.requestId = requestId\n defineSDKErrorBrand(this)\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, new.target)\n }\n }\n\n getUserMessage(): string {\n return this.userMessage || this.message\n }\n\n toJSON() {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n status: this.status,\n details: this.details,\n userMessage: this.userMessage,\n suggestion: this.suggestion,\n ...(this.requestId !== undefined && { requestId: this.requestId }),\n ...(this.kind !== undefined && { kind: this.kind }),\n ...(this.reason !== undefined && { reason: this.reason }),\n ...(this.rawReason !== undefined && { rawReason: this.rawReason }),\n ...(this.apiReason !== undefined && { apiReason: this.apiReason }),\n ...(this.retryable !== undefined && { retryable: this.retryable }),\n ...(this.retryAfter !== undefined && { retryAfter: this.retryAfter }),\n }\n }\n}\n\n/**\n * Canonical Cart/Checkout/PaymentSession error reasons. This public SDK mirror\n * intentionally does not import the private contracts package; parity is\n * enforced by a type test.\n */\nexport const COMMERCE_ERROR_CODES = [\n 'validation_failed',\n 'bad_request',\n 'unauthorized',\n 'forbidden',\n 'account_suspended',\n 'key_invalid',\n 'pat_tenant_header_forbidden',\n 'tenant_mismatch',\n 'test_tenant_expired',\n 'token_invalid',\n 'token_expired',\n 'origin_not_allowed',\n 'server_credentials_required',\n 'role_denied',\n 'scope_denied',\n 'feature_disabled',\n 'not_found',\n 'conflict',\n 'locked',\n 'cart_revision_conflict',\n 'rate_limit_exceeded',\n 'usage_limit_exceeded',\n 'service_unavailable',\n 'idempotency_conflict',\n 'idempotency_in_progress',\n 'idempotency_key_required',\n 'invalid_idempotency_key',\n 'cart_not_active',\n 'cart_locked',\n 'cart_empty',\n 'cart_market_unavailable',\n 'cart_market_mismatch',\n 'checkout_not_open',\n 'checkout_already_open',\n 'payment_slot_held',\n 'reservation_expired',\n 'payment_session_not_cancelable',\n 'payment_session_conflict',\n 'provider_identity_mismatch',\n 'managed_refund_attestation_forbidden',\n 'payment_method_unavailable',\n 'provider_unavailable',\n 'lock_timeout',\n 'price_changed',\n 'pricing_fact_in_use',\n 'insufficient_stock',\n 'reservation_conflict',\n 'stock_lock_unavailable',\n 'variant_not_found',\n 'variant_stock_write_failed',\n 'stock_invariant_violation',\n 'payment_confirmation_in_flight',\n 'checkout_reservation_release_requires_transaction',\n 'admission_metadata_invalid',\n 'admission_metadata_required',\n 'admission_not_eligible',\n 'admission_eligibility_unavailable',\n 'admission_authority_unavailable',\n 'admission_customer_binding_required',\n 'admission_eligibility_unproven',\n 'capacity_exceeded',\n 'admission_required',\n 'occurrence_lock_unavailable',\n 'occurrence_not_open',\n 'admission_type_capacity_exceeded',\n 'admission_type_occurrence_mismatch',\n 'admission_hold_expired',\n 'admission_hold_checkout_item_conflict',\n 'admission_hold_checkout_conflict',\n 'admission_hold_quantity_mismatch',\n 'admission_hold_unbound',\n 'admission_hold_missing',\n 'admission_hold_checkout_item_missing',\n 'admission_hold_expiry_failed',\n 'admission_hold_expiry_requires_transaction',\n 'admission_hold_line_item_mismatch',\n 'admission_materialization_failed',\n 'variant_inactive',\n 'variant_product_mismatch',\n 'product_not_public',\n 'product_not_eligible',\n 'purchase_limit_exceeded',\n 'market_not_found',\n 'market_shipping_currency_unsupported',\n 'missing_market_rate',\n 'missing_shipping_amount',\n 'no_enabled_payment_provider',\n 'product_market_unavailable',\n 'unsupported_currency',\n 'missing_price_row',\n 'payment_provider_currency_unsupported',\n 'discount_code_not_found',\n 'discount_not_started',\n 'discount_expired',\n 'discount_usage_limit',\n 'discount_per_customer_limit',\n 'discount_customer_required',\n 'discount_first_order_only',\n 'discount_customer_not_eligible',\n 'discount_customer_excluded',\n 'discount_items_required',\n 'discount_product_not_eligible',\n 'discount_product_excluded',\n 'discount_min_order_amount',\n 'discount_currency_scope_required',\n 'discount_allocation_method_unsupported',\n 'currency_mismatch',\n 'customer_token_required',\n 'market_required',\n 'server_derived',\n 'internal_error',\n] as const\n\nexport type CommerceErrorCode = (typeof COMMERCE_ERROR_CODES)[number]\n\ntype CommerceSDKErrorBase = SDKError & {\n readonly kind: 'commerce'\n readonly requestId: string\n readonly retryable: boolean\n readonly retryAfter?: number\n readonly details?: Record<string, unknown>\n}\n\nexport type CommerceSDKError = CommerceSDKErrorBase &\n (\n | { readonly reason: CommerceErrorCode; readonly rawReason?: never }\n | {\n readonly reason: 'unknown_commerce_error'\n readonly rawReason: string\n }\n )\n\nconst COMMERCE_ERROR_CODE_SET: ReadonlySet<string> = new Set(\n COMMERCE_ERROR_CODES,\n)\nconst COMMERCE_ERROR_ENVELOPE_KEYS = new Set([\n 'error',\n 'reason',\n 'requestId',\n 'retryable',\n 'details',\n])\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nexport type CommerceErrorEnvelope = {\n error: string\n reason: string\n requestId: string\n retryable: boolean\n details?: Record<string, unknown>\n}\n\nfunction commerceProtocolError(\n issue: string,\n trustedRequestId?: string,\n): SDKError {\n return createApiError(\n 'Invalid canonical commerce error response.',\n 502,\n { protocol: 'commerce-error-envelope', issue },\n 'The server returned an incompatible commerce error response.',\n 'Verify that the Console commerce contract is deployed before using this SDK version.',\n trustedRequestId,\n )\n}\n\n/** @internal Strictly parse a canonical commerce error without retaining its raw body. */\nexport function parseCommerceErrorEnvelope(\n body: unknown,\n headerRequestId?: string,\n): CommerceErrorEnvelope {\n if (headerRequestId === undefined) {\n throw commerceProtocolError('missing_request_id_header')\n }\n if (headerRequestId.length === 0) {\n throw commerceProtocolError('empty_request_id_header')\n }\n if (!isPlainRecord(body)) {\n throw commerceProtocolError('expected_object', headerRequestId)\n }\n if (Object.keys(body).some((key) => !COMMERCE_ERROR_ENVELOPE_KEYS.has(key))) {\n throw commerceProtocolError('unexpected_field', headerRequestId)\n }\n if (\n typeof body.error !== 'string' ||\n body.error.length === 0 ||\n typeof body.reason !== 'string' ||\n body.reason.length === 0 ||\n typeof body.requestId !== 'string' ||\n body.requestId.length === 0 ||\n (body.retryable !== undefined && typeof body.retryable !== 'boolean') ||\n (body.details !== undefined && !isPlainRecord(body.details))\n ) {\n throw commerceProtocolError('invalid_field', headerRequestId)\n }\n\n if (headerRequestId !== undefined && headerRequestId !== body.requestId) {\n throw commerceProtocolError('request_id_mismatch', headerRequestId)\n }\n\n return {\n error: body.error,\n reason: body.reason,\n requestId: body.requestId,\n retryable: body.retryable === true,\n ...(body.details === undefined ? {} : { details: body.details }),\n }\n}\n\n/** @internal Validate and apply the canonical commerce error envelope. */\nexport function enhanceCommerceError(\n error: SDKError,\n body: unknown,\n headerRequestId?: string,\n): SDKError {\n const envelope = parseCommerceErrorEnvelope(body, headerRequestId)\n\n const known = COMMERCE_ERROR_CODE_SET.has(envelope.reason)\n Object.assign(error, {\n code: envelope.reason,\n kind: 'commerce' as const,\n reason: known\n ? (envelope.reason as CommerceErrorCode)\n : 'unknown_commerce_error',\n ...(known ? {} : { rawReason: envelope.reason }),\n requestId: envelope.requestId,\n retryable: envelope.retryable,\n details: envelope.details,\n })\n return error\n}\n\n/** @internal Apply a non-commerce reason without canonical-commerce validation. */\nexport function enhanceNonCommerceError(\n error: SDKError,\n reason: unknown,\n): SDKError {\n if (typeof reason === 'string') Object.assign(error, { apiReason: reason })\n return error\n}\n\n/**\n * Read the server-provided machine reason across strict commerce and\n * non-commerce SDK errors. Unknown commerce reasons are returned verbatim.\n */\nexport function getSDKErrorReason(error: SDKError): string | undefined {\n if (error.kind !== 'commerce') return error.apiReason\n return error.reason === 'unknown_commerce_error'\n ? error.rawReason\n : error.reason\n}\n\nexport function isCommerceSDKError(error: unknown): error is CommerceSDKError {\n if (!isSDKError(error) || error.kind !== 'commerce') return false\n if (\n typeof error.requestId !== 'string' ||\n typeof error.retryable !== 'boolean' ||\n (error.retryAfter !== undefined &&\n (!Number.isSafeInteger(error.retryAfter) || error.retryAfter < 0)) ||\n typeof error.reason !== 'string'\n ) {\n return false\n }\n return error.reason === 'unknown_commerce_error'\n ? typeof error.rawReason === 'string'\n : COMMERCE_ERROR_CODE_SET.has(error.reason) && error.rawReason === undefined\n}\n\nexport class NetworkError extends SDKError {\n constructor(\n message: string,\n status?: number,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n ) {\n super('NETWORK_ERROR', message, status, details, userMessage, suggestion)\n this.name = 'NetworkError'\n defineSDKErrorType(this, 'NetworkError')\n }\n}\n\nexport class ValidationError extends SDKError {\n constructor(\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n status = 400,\n ) {\n super('VALIDATION_ERROR', message, status, details, userMessage, suggestion)\n this.name = 'ValidationError'\n defineSDKErrorType(this, 'ValidationError')\n }\n}\n\nexport class ApiError extends SDKError {\n constructor(\n message: string,\n status: number,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n ) {\n super(\n 'API_ERROR',\n message,\n status,\n details,\n userMessage,\n suggestion,\n requestId,\n )\n this.name = 'ApiError'\n defineSDKErrorType(this, 'ApiError')\n }\n}\n\nexport class ConfigError extends SDKError {\n constructor(\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n ) {\n super('CONFIG_ERROR', message, undefined, details, userMessage, suggestion)\n this.name = 'ConfigError'\n defineSDKErrorType(this, 'ConfigError')\n }\n}\n\nexport class TimeoutError extends SDKError {\n constructor(\n message = 'Request timed out.',\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n ) {\n super('TIMEOUT_ERROR', message, 408, details, userMessage, suggestion)\n this.name = 'TimeoutError'\n defineSDKErrorType(this, 'TimeoutError')\n }\n}\n\nexport class GoneError extends SDKError {\n constructor(\n message = 'The requested resource is no longer available.',\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n ) {\n super('GONE_ERROR', message, 410, details, userMessage, suggestion)\n this.name = 'GoneError'\n defineSDKErrorType(this, 'GoneError')\n }\n}\n\nexport class ServiceUnavailableError extends SDKError {\n readonly retryAfter?: number\n\n constructor(\n message = 'Service temporarily unavailable.',\n retryAfter?: number,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n ) {\n super(\n 'SERVICE_UNAVAILABLE_ERROR',\n message,\n 503,\n details,\n userMessage,\n suggestion,\n )\n this.name = 'ServiceUnavailableError'\n this.retryAfter = retryAfter\n defineSDKErrorType(this, 'ServiceUnavailableError')\n }\n}\n\nexport class UsageLimitError extends SDKError {\n readonly usage: { limit: number; current: number; remaining: number }\n\n constructor(\n message: string,\n usage: { limit: number; current: number; remaining: number },\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n ) {\n super('USAGE_LIMIT_ERROR', message, 429, details, userMessage, suggestion)\n this.name = 'UsageLimitError'\n this.usage = usage\n defineSDKErrorType(this, 'UsageLimitError')\n }\n\n toJSON() {\n return {\n ...super.toJSON(),\n usage: this.usage,\n }\n }\n}\n\nexport class AuthError extends SDKError {\n constructor(\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n ) {\n super(\n 'auth_error',\n message,\n 401,\n details,\n userMessage,\n suggestion,\n requestId,\n )\n this.name = 'AuthError'\n defineSDKErrorType(this, 'AuthError')\n }\n}\n\nexport class PermissionError extends SDKError {\n constructor(\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n ) {\n super(\n 'permission_error',\n message,\n 403,\n details,\n userMessage,\n suggestion,\n requestId,\n )\n this.name = 'PermissionError'\n defineSDKErrorType(this, 'PermissionError')\n }\n}\n\nexport class NotFoundError extends SDKError {\n constructor(\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n ) {\n super(\n 'not_found',\n message,\n 404,\n details,\n userMessage,\n suggestion,\n requestId,\n )\n this.name = 'NotFoundError'\n defineSDKErrorType(this, 'NotFoundError')\n }\n}\n\nexport class ConflictError extends SDKError {\n constructor(\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n ) {\n super('conflict', message, 409, details, userMessage, suggestion, requestId)\n this.name = 'ConflictError'\n defineSDKErrorType(this, 'ConflictError')\n }\n}\n\nexport class RateLimitError extends SDKError {\n readonly retryAfter?: number\n\n constructor(\n message: string,\n retryAfter?: number,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n ) {\n super(\n 'rate_limit_exceeded',\n message,\n 429,\n details,\n userMessage,\n suggestion,\n requestId,\n )\n this.name = 'RateLimitError'\n this.retryAfter = retryAfter\n defineSDKErrorType(this, 'RateLimitError')\n }\n}\n\nfunction hasBrandedSDKErrorShape(error: unknown): error is SDKError {\n if (error === null || typeof error !== 'object') return false\n\n const candidate = error as Record<PropertyKey, unknown>\n return (\n candidate[SDK_ERROR_BRAND] === true &&\n typeof candidate.name === 'string' &&\n typeof candidate.code === 'string' &&\n typeof candidate.message === 'string' &&\n (candidate.status === undefined || typeof candidate.status === 'number') &&\n (candidate.userMessage === undefined ||\n typeof candidate.userMessage === 'string') &&\n (candidate.suggestion === undefined ||\n typeof candidate.suggestion === 'string') &&\n (candidate.requestId === undefined ||\n typeof candidate.requestId === 'string') &&\n (candidate.kind === undefined || candidate.kind === 'commerce') &&\n (candidate.reason === undefined || typeof candidate.reason === 'string') &&\n (candidate.rawReason === undefined ||\n typeof candidate.rawReason === 'string') &&\n (candidate.apiReason === undefined ||\n typeof candidate.apiReason === 'string') &&\n (candidate.retryable === undefined ||\n typeof candidate.retryable === 'boolean') &&\n (candidate.retryAfter === undefined ||\n typeof candidate.retryAfter === 'number') &&\n typeof candidate.getUserMessage === 'function' &&\n typeof candidate.toJSON === 'function'\n )\n}\n\nfunction hasSDKErrorType(error: unknown, type: SDKErrorType): boolean {\n return (\n hasBrandedSDKErrorShape(error) &&\n (error as unknown as Record<PropertyKey, unknown>)[SDK_ERROR_TYPE_BRAND] ===\n type\n )\n}\n\nexport function isSDKError(error: unknown): error is SDKError {\n return error instanceof SDKError || hasBrandedSDKErrorShape(error)\n}\n\nexport function isNetworkError(error: unknown): error is NetworkError {\n return error instanceof NetworkError || hasSDKErrorType(error, 'NetworkError')\n}\n\nexport function isValidationError(error: unknown): error is ValidationError {\n if (\n error instanceof ValidationError ||\n hasSDKErrorType(error, 'ValidationError')\n ) {\n return true\n }\n if (error == null || typeof error !== 'object') return false\n\n const candidate = error as {\n code?: unknown\n name?: unknown\n message?: unknown\n getUserMessage?: unknown\n toJSON?: unknown\n }\n return (\n candidate.name === 'ValidationError' &&\n candidate.code === 'VALIDATION_ERROR' &&\n typeof candidate.message === 'string' &&\n typeof candidate.getUserMessage === 'function' &&\n typeof candidate.toJSON === 'function'\n )\n}\n\nexport function isApiError(error: unknown): error is ApiError {\n return error instanceof ApiError || hasSDKErrorType(error, 'ApiError')\n}\n\nexport function isConfigError(error: unknown): error is ConfigError {\n return error instanceof ConfigError || hasSDKErrorType(error, 'ConfigError')\n}\n\nexport function isTimeoutError(error: unknown): error is TimeoutError {\n return error instanceof TimeoutError || hasSDKErrorType(error, 'TimeoutError')\n}\n\nexport function isGoneError(error: unknown): error is GoneError {\n return error instanceof GoneError || hasSDKErrorType(error, 'GoneError')\n}\n\nexport function isServiceUnavailableError(\n error: unknown,\n): error is ServiceUnavailableError {\n return (\n error instanceof ServiceUnavailableError ||\n hasSDKErrorType(error, 'ServiceUnavailableError')\n )\n}\n\nexport function isUsageLimitError(error: unknown): error is UsageLimitError {\n return (\n error instanceof UsageLimitError ||\n hasSDKErrorType(error, 'UsageLimitError')\n )\n}\n\nexport function isAuthError(error: unknown): error is AuthError {\n return error instanceof AuthError || hasSDKErrorType(error, 'AuthError')\n}\n\nexport function isPermissionError(error: unknown): error is PermissionError {\n return (\n error instanceof PermissionError ||\n hasSDKErrorType(error, 'PermissionError')\n )\n}\n\nexport function isNotFoundError(error: unknown): error is NotFoundError {\n return (\n error instanceof NotFoundError || hasSDKErrorType(error, 'NotFoundError')\n )\n}\n\nexport function isConflictError(error: unknown): error is ConflictError {\n return (\n error instanceof ConflictError || hasSDKErrorType(error, 'ConflictError')\n )\n}\n\nexport function isRateLimitError(error: unknown): error is RateLimitError {\n return (\n error instanceof RateLimitError || hasSDKErrorType(error, 'RateLimitError')\n )\n}\n\nexport const createNetworkError = (\n message: string,\n status?: number,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n) => new NetworkError(message, status, details, userMessage, suggestion)\n\nexport const createValidationError = (\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n status?: number,\n) => new ValidationError(message, details, userMessage, suggestion, status)\n\nexport const createApiError = (\n message: string,\n status: number,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n) => new ApiError(message, status, details, userMessage, suggestion, requestId)\n\nexport const createConfigError = (\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n) => new ConfigError(message, details, userMessage, suggestion)\n\nexport const createTimeoutError = (\n message?: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n) => new TimeoutError(message, details, userMessage, suggestion)\n\nexport const createGoneError = (\n message?: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n) => new GoneError(message, details, userMessage, suggestion)\n\nexport const createServiceUnavailableError = (\n message?: string,\n retryAfter?: number,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n) =>\n new ServiceUnavailableError(\n message,\n retryAfter,\n details,\n userMessage,\n suggestion,\n )\n\nexport const createUsageLimitError = (\n message: string,\n usage: { limit: number; current: number; remaining: number },\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n) => new UsageLimitError(message, usage, details, userMessage, suggestion)\n\nexport const createAuthError = (\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n) => new AuthError(message, details, userMessage, suggestion, requestId)\n\nexport const createPermissionError = (\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n) => new PermissionError(message, details, userMessage, suggestion, requestId)\n\nexport const createNotFoundError = (\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n) => new NotFoundError(message, details, userMessage, suggestion, requestId)\n\nexport const createConflictError = (\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n) => new ConflictError(message, details, userMessage, suggestion, requestId)\n\nexport const createRateLimitError = (\n message: string,\n retryAfter?: number,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n) =>\n new RateLimitError(\n message,\n retryAfter,\n details,\n userMessage,\n suggestion,\n requestId,\n )\n"],"mappings":"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","names":["port"]}
|
|
1
|
+
{"version":3,"sources":["../src/embedded-admin/index.ts","../src/core/errors.ts","../src/embedded-admin/actions.ts"],"sourcesContent":["import { createValidationError } from '../core/internal/errors'\nimport {\n EMBEDDED_ADMIN_ACTION_PROTOCOL_VERSION,\n EMBEDDED_ADMIN_ACTION_CAPABILITY,\n normalizeEmbeddedAdminActions,\n normalizeEmbeddedAdminExecutionContext,\n type EmbeddedAdminAction,\n type EmbeddedAdminExecutionContext,\n} from './actions'\n\nexport * from './actions'\n\nexport const EMBEDDED_ADMIN_PROTOCOL_VERSION = 1 as const\nexport const EMBEDDED_ADMIN_CHALLENGE_MESSAGE =\n '01.embedded-admin.challenge' as const\nexport const EMBEDDED_ADMIN_READY_MESSAGE = '01.embedded-admin.ready' as const\nexport const EMBEDDED_ADMIN_SESSION_MESSAGE =\n '01.embedded-admin.session' as const\nexport const EMBEDDED_ADMIN_SESSION_TTL_SECONDS = 60 as const\nexport const EMBEDDED_ADMIN_APP_KEY = 'primary' as const\n\nconst DEFAULT_RECEIVER_TIMEOUT_MS = 35_000\nconst MAX_RECEIVER_TIMEOUT_MS = 120_000\nconst MAX_LABEL_LENGTH = 80\nconst MAX_PATH_LENGTH = 512\n\nexport type EmbeddedAdminChallengeMessage = {\n type: typeof EMBEDDED_ADMIN_CHALLENGE_MESSAGE\n version: typeof EMBEDDED_ADMIN_PROTOCOL_VERSION\n requestId: string\n}\n\nexport type EmbeddedAdminReadyMessage = {\n type: typeof EMBEDDED_ADMIN_READY_MESSAGE\n version: typeof EMBEDDED_ADMIN_PROTOCOL_VERSION\n requestId: string\n}\n\nexport type EmbeddedAdminSessionMessage = {\n type: typeof EMBEDDED_ADMIN_SESSION_MESSAGE\n version: typeof EMBEDDED_ADMIN_PROTOCOL_VERSION\n requestId: string\n token: string\n}\n\n/** Exact execution roles; this list grants no platform data permissions. */\nexport const EMBEDDED_ADMIN_TENANT_ROLES = [\n 'tenant-admin',\n 'tenant-editor',\n 'tenant-viewer',\n] as const\nexport type EmbeddedAdminTenantRole =\n (typeof EMBEDDED_ADMIN_TENANT_ROLES)[number]\n\n/** Missing legacy settings retain administrator-only execution; invalid settings fail closed. */\nexport function normalizeEmbeddedAdminAllowedRoles(\n value: unknown,\n): EmbeddedAdminTenantRole[] | null {\n if (value === undefined || value === null) return ['tenant-admin']\n if (\n !Array.isArray(value) ||\n value.some((role) => !EMBEDDED_ADMIN_TENANT_ROLES.includes(role))\n )\n return null\n return EMBEDDED_ADMIN_TENANT_ROLES.filter((role) => value.includes(role))\n}\n\nexport type EmbeddedAdminBindingConfiguration = {\n /** Explicit opt-in; missing values keep sandbox downloads disabled. */\n allowDownloads?: boolean\n allowedRoles?: EmbeddedAdminTenantRole[]\n enabled: boolean\n label: string\n origin: string\n path: string\n actions?: EmbeddedAdminAction[]\n}\n\nexport type EmbeddedAdminSessionReceipt = {\n requestId: string\n token: string\n}\n\nexport type EmbeddedAdminExecutionReceipt = EmbeddedAdminSessionReceipt & {\n execution: EmbeddedAdminExecutionContext\n}\n\nexport type ReceiveEmbeddedAdminSessionOptions = {\n /** Test fixtures only. Production integrations must keep HTTPS enforcement. */\n allowLoopbackHttp?: boolean\n /** Exact Console origin configured by the receiver deployment. */\n consoleOrigin: string\n /** Cancels the one-shot receiver and closes every transferred port. */\n signal?: AbortSignal\n /** Defaults to 35 seconds and is capped at 120 seconds. */\n timeoutMs?: number\n}\n\nfunction isLoopbackHostname(hostname: string): boolean {\n return (\n hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '[::1]'\n )\n}\n\nexport function normalizeEmbeddedAdminExactOrigin(\n value: unknown,\n options: { allowLoopbackHttp?: boolean } = {},\n): string | null {\n if (typeof value !== 'string') return null\n const trimmed = value.trim()\n if (!trimmed || trimmed.length > 2048) return null\n\n let parsed: URL\n try {\n parsed = new URL(trimmed)\n } catch {\n return null\n }\n\n const allowedProtocol =\n parsed.protocol === 'https:' ||\n (options.allowLoopbackHttp === true &&\n parsed.protocol === 'http:' &&\n isLoopbackHostname(parsed.hostname))\n if (!allowedProtocol || parsed.hostname.includes('*')) return null\n if (parsed.username || parsed.password || parsed.search || parsed.hash) {\n return null\n }\n if (parsed.pathname !== '/' || trimmed.endsWith('/')) return null\n\n return parsed.origin\n}\n\nexport function normalizeEmbeddedAdminRelativePath(\n value: unknown,\n): string | null {\n if (typeof value !== 'string') return null\n const trimmed = value.trim()\n if (\n !trimmed.startsWith('/') ||\n trimmed.startsWith('//') ||\n trimmed.length > MAX_PATH_LENGTH\n ) {\n return null\n }\n\n let parsed: URL\n try {\n parsed = new URL(trimmed, 'https://embedded.invalid')\n } catch {\n return null\n }\n\n if (\n parsed.origin !== 'https://embedded.invalid' ||\n parsed.pathname.startsWith('//') ||\n parsed.search ||\n parsed.hash ||\n parsed.username ||\n parsed.password\n ) {\n return null\n }\n\n return parsed.pathname\n}\n\nexport function normalizeEmbeddedAdminBindingConfiguration(\n value: unknown,\n options: {\n allowLoopbackConsoleHttp?: boolean\n consoleOrigin?: string\n } = {},\n): EmbeddedAdminBindingConfiguration & { allowDownloads: boolean } {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw createValidationError('Embedded admin binding must be an object.')\n }\n\n const input = value as Record<string, unknown>\n if (\n input.allowDownloads !== undefined &&\n typeof input.allowDownloads !== 'boolean'\n ) {\n throw createValidationError('allowDownloads must be a boolean.')\n }\n const allowedRoles = normalizeEmbeddedAdminAllowedRoles(input.allowedRoles)\n if (!allowedRoles)\n throw createValidationError(\n 'Embedded admin allowedRoles must contain only tenant execution roles.',\n )\n const label = typeof input.label === 'string' ? input.label.trim() : ''\n const origin = normalizeEmbeddedAdminExactOrigin(input.origin)\n const path = normalizeEmbeddedAdminRelativePath(input.path)\n const consoleOrigin = options.consoleOrigin\n ? normalizeEmbeddedAdminExactOrigin(options.consoleOrigin, {\n allowLoopbackHttp: options.allowLoopbackConsoleHttp === true,\n })\n : null\n\n if (!label || label.length > MAX_LABEL_LENGTH) {\n throw createValidationError(\n `Embedded admin label must be between 1 and ${MAX_LABEL_LENGTH} characters.`,\n )\n }\n if (!origin) {\n throw createValidationError(\n 'Embedded admin origin must be an exact HTTPS origin without a path, query, fragment, wildcard, or credentials.',\n )\n }\n if (!path) {\n throw createValidationError(\n 'Embedded admin path must begin with / and must not include a query or fragment.',\n )\n }\n if (consoleOrigin && origin === consoleOrigin) {\n throw createValidationError(\n 'Embedded admin origin must be different from the Console origin.',\n )\n }\n\n return {\n allowedRoles,\n enabled: input.enabled !== false,\n allowDownloads: input.allowDownloads === true,\n label,\n origin,\n path,\n ...(input.actions === undefined\n ? {}\n : { actions: normalizeEmbeddedAdminActions(input.actions) }),\n }\n}\n\nexport function isEmbeddedAdminChallengeMessage(\n value: unknown,\n): value is EmbeddedAdminChallengeMessage {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false\n const message = value as Record<string, unknown>\n return (\n message.type === EMBEDDED_ADMIN_CHALLENGE_MESSAGE &&\n message.version === EMBEDDED_ADMIN_PROTOCOL_VERSION &&\n typeof message.requestId === 'string' &&\n message.requestId.length >= 16 &&\n message.requestId.length <= 128\n )\n}\n\nexport function isEmbeddedAdminReadyMessage(\n value: unknown,\n): value is EmbeddedAdminReadyMessage {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false\n const message = value as Record<string, unknown>\n return (\n message.type === EMBEDDED_ADMIN_READY_MESSAGE &&\n message.version === EMBEDDED_ADMIN_PROTOCOL_VERSION &&\n typeof message.requestId === 'string' &&\n message.requestId.length >= 16 &&\n message.requestId.length <= 128\n )\n}\n\nexport function isEmbeddedAdminSessionMessage(\n value: unknown,\n): value is EmbeddedAdminSessionMessage {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false\n const message = value as Record<string, unknown>\n return (\n message.type === EMBEDDED_ADMIN_SESSION_MESSAGE &&\n message.version === EMBEDDED_ADMIN_PROTOCOL_VERSION &&\n typeof message.requestId === 'string' &&\n message.requestId.length >= 16 &&\n message.requestId.length <= 128 &&\n typeof message.token === 'string' &&\n message.token.length > 0\n )\n}\n\n/**\n * Receives one Console assertion through the exact parent/origin challenge\n * channel. Forward the returned token immediately to the receiver backend;\n * never persist, log, decode, or use it as Console API authority in-browser.\n */\nexport function receiveEmbeddedAdminSession(\n options: ReceiveEmbeddedAdminSessionOptions,\n): Promise<EmbeddedAdminSessionReceipt> {\n return receiveSession(options, false)\n}\n\n/** Receives a v2 action only. It never silently accepts an identity-only launch. */\nexport function receiveEmbeddedAdminExecution(\n options: ReceiveEmbeddedAdminSessionOptions,\n): Promise<EmbeddedAdminExecutionReceipt> {\n return receiveSession(options, true) as Promise<EmbeddedAdminExecutionReceipt>\n}\n\nfunction receiveSession(\n options: ReceiveEmbeddedAdminSessionOptions,\n action: boolean,\n): Promise<EmbeddedAdminSessionReceipt | EmbeddedAdminExecutionReceipt> {\n if (typeof window === 'undefined' || window.parent === window) {\n return Promise.reject(\n createValidationError(\n 'receiveEmbeddedAdminSession must run inside an embedded browser frame.',\n ),\n )\n }\n\n const consoleOrigin = normalizeEmbeddedAdminExactOrigin(\n options.consoleOrigin,\n { allowLoopbackHttp: options.allowLoopbackHttp === true },\n )\n if (!consoleOrigin) {\n return Promise.reject(\n createValidationError('consoleOrigin must be one exact HTTPS origin.'),\n )\n }\n\n const timeoutMs = options.timeoutMs ?? DEFAULT_RECEIVER_TIMEOUT_MS\n if (\n !Number.isInteger(timeoutMs) ||\n timeoutMs <= 0 ||\n timeoutMs > MAX_RECEIVER_TIMEOUT_MS\n ) {\n return Promise.reject(\n createValidationError(\n `timeoutMs must be an integer between 1 and ${MAX_RECEIVER_TIMEOUT_MS}.`,\n ),\n )\n }\n\n return new Promise((resolve, reject) => {\n const ports = new Set<MessagePort>()\n let settled = false\n\n const closePorts = () => {\n for (const port of ports) port.close()\n ports.clear()\n }\n const cleanup = () => {\n window.removeEventListener('message', acceptChallenge)\n options.signal?.removeEventListener('abort', abort)\n clearTimeout(timer)\n closePorts()\n }\n const finish = (\n receipt: EmbeddedAdminSessionReceipt | EmbeddedAdminExecutionReceipt,\n ) => {\n if (settled) return\n settled = true\n cleanup()\n resolve(receipt)\n }\n const fail = (error: Error) => {\n if (settled) return\n settled = true\n cleanup()\n reject(error)\n }\n const abort = () =>\n fail(new Error('Embedded admin session receipt aborted.'))\n const acceptSession = (\n event: MessageEvent<unknown>,\n expectedRequestId: string,\n ) => {\n if (action) {\n const message = event.data as Record<string, unknown> | null\n if (\n !message ||\n message.type !== EMBEDDED_ADMIN_SESSION_MESSAGE ||\n message.version !== EMBEDDED_ADMIN_ACTION_PROTOCOL_VERSION ||\n message.requestId !== expectedRequestId ||\n typeof message.token !== 'string' ||\n !message.token\n )\n return\n try {\n finish({\n requestId: expectedRequestId,\n token: message.token,\n execution: normalizeEmbeddedAdminExecutionContext(\n message.execution,\n ),\n })\n } catch {\n fail(new Error('Invalid embedded admin execution message.'))\n }\n } else {\n if (\n !isEmbeddedAdminSessionMessage(event.data) ||\n event.data.requestId !== expectedRequestId\n )\n return\n finish({ requestId: event.data.requestId, token: event.data.token })\n }\n }\n const acceptChallenge = (event: MessageEvent<unknown>) => {\n if (\n event.source !== window.parent ||\n event.origin !== consoleOrigin ||\n event.ports.length !== 1\n ) {\n for (const port of event.ports) port.close()\n return\n }\n\n const challenge = event.data as Record<string, unknown> | null\n const actionChallenge =\n challenge?.type === EMBEDDED_ADMIN_CHALLENGE_MESSAGE &&\n challenge.version === EMBEDDED_ADMIN_ACTION_PROTOCOL_VERSION &&\n typeof challenge.requestId === 'string' &&\n challenge.requestId.length >= 16 &&\n challenge.requestId.length <= 128\n const supported = action\n ? actionChallenge &&\n Array.isArray(challenge?.capabilities) &&\n challenge.capabilities.length === 1 &&\n challenge.capabilities[0] === EMBEDDED_ADMIN_ACTION_CAPABILITY\n : isEmbeddedAdminChallengeMessage(event.data)\n if (!supported) {\n if (actionChallenge)\n event.ports[0]!.postMessage({\n type: '01.embedded-admin.error',\n version: 2,\n requestId: challenge.requestId,\n reason: 'unsupported',\n })\n for (const port of event.ports) port.close()\n return\n }\n\n const port = event.ports[0]!\n const requestId = (event.data as EmbeddedAdminChallengeMessage).requestId\n ports.add(port)\n port.addEventListener('message', (message) => {\n acceptSession(message, requestId)\n })\n port.start()\n port.postMessage({\n type: EMBEDDED_ADMIN_READY_MESSAGE,\n version: action\n ? EMBEDDED_ADMIN_ACTION_PROTOCOL_VERSION\n : EMBEDDED_ADMIN_PROTOCOL_VERSION,\n requestId,\n ...(action ? { capabilities: [EMBEDDED_ADMIN_ACTION_CAPABILITY] } : {}),\n })\n }\n\n const timer = setTimeout(() => {\n fail(new Error('Timed out waiting for an embedded admin session.'))\n }, timeoutMs)\n\n if (options.signal?.aborted) {\n abort()\n return\n }\n options.signal?.addEventListener('abort', abort, { once: true })\n window.addEventListener('message', acceptChallenge)\n })\n}\n","const SDK_ERROR_BRAND = Symbol.for('@01.software/sdk/SDKError')\nconst SDK_ERROR_TYPE_BRAND = Symbol.for('@01.software/sdk/SDKError.type')\n\ntype SDKErrorType =\n | 'NetworkError'\n | 'ValidationError'\n | 'ApiError'\n | 'ConfigError'\n | 'TimeoutError'\n | 'GoneError'\n | 'ServiceUnavailableError'\n | 'UsageLimitError'\n | 'AuthError'\n | 'PermissionError'\n | 'NotFoundError'\n | 'ConflictError'\n | 'RateLimitError'\n\nfunction defineSDKErrorBrand(error: SDKError): void {\n Object.defineProperty(error, SDK_ERROR_BRAND, {\n value: true,\n enumerable: false,\n configurable: false,\n writable: false,\n })\n}\n\nfunction defineSDKErrorType(error: SDKError, type: SDKErrorType): void {\n Object.defineProperty(error, SDK_ERROR_TYPE_BRAND, {\n value: type,\n enumerable: false,\n configurable: false,\n writable: false,\n })\n}\n\nexport class SDKError extends Error {\n readonly code: string\n readonly status?: number\n readonly details?: unknown\n readonly userMessage?: string\n readonly suggestion?: string\n readonly requestId?: string\n readonly kind?: 'commerce'\n readonly reason?: CommerceErrorCode | 'unknown_commerce_error'\n readonly rawReason?: string\n /** Machine-readable reason from a non-commerce API response. */\n readonly apiReason?: string\n readonly retryable?: boolean\n readonly retryAfter?: number\n\n constructor(\n code: string,\n message: string,\n status?: number,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n ) {\n super(message)\n this.name = 'SDKError'\n this.code = code\n this.status = status\n this.details = details\n this.userMessage = userMessage\n this.suggestion = suggestion\n this.requestId = requestId\n defineSDKErrorBrand(this)\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, new.target)\n }\n }\n\n getUserMessage(): string {\n return this.userMessage || this.message\n }\n\n toJSON() {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n status: this.status,\n details: this.details,\n userMessage: this.userMessage,\n suggestion: this.suggestion,\n ...(this.requestId !== undefined && { requestId: this.requestId }),\n ...(this.kind !== undefined && { kind: this.kind }),\n ...(this.reason !== undefined && { reason: this.reason }),\n ...(this.rawReason !== undefined && { rawReason: this.rawReason }),\n ...(this.apiReason !== undefined && { apiReason: this.apiReason }),\n ...(this.retryable !== undefined && { retryable: this.retryable }),\n ...(this.retryAfter !== undefined && { retryAfter: this.retryAfter }),\n }\n }\n}\n\n/**\n * Canonical Cart/Checkout/PaymentSession error reasons. This public SDK mirror\n * intentionally does not import the private contracts package; parity is\n * enforced by a type test.\n */\nexport const COMMERCE_ERROR_CODES = [\n 'validation_failed',\n 'bad_request',\n 'unauthorized',\n 'forbidden',\n 'account_suspended',\n 'key_invalid',\n 'pat_tenant_header_forbidden',\n 'tenant_mismatch',\n 'test_tenant_expired',\n 'token_invalid',\n 'token_expired',\n 'origin_not_allowed',\n 'server_credentials_required',\n 'role_denied',\n 'scope_denied',\n 'feature_disabled',\n 'not_found',\n 'conflict',\n 'locked',\n 'cart_revision_conflict',\n 'rate_limit_exceeded',\n 'usage_limit_exceeded',\n 'service_unavailable',\n 'idempotency_conflict',\n 'idempotency_in_progress',\n 'idempotency_key_required',\n 'invalid_idempotency_key',\n 'cart_not_active',\n 'cart_locked',\n 'cart_empty',\n 'shipping_address_required',\n 'cart_market_unavailable',\n 'cart_market_mismatch',\n 'checkout_not_open',\n 'checkout_already_open',\n 'payment_slot_held',\n 'reservation_expired',\n 'payment_session_not_cancelable',\n 'payment_session_conflict',\n 'provider_identity_mismatch',\n 'managed_refund_attestation_forbidden',\n 'payment_method_unavailable',\n 'provider_unavailable',\n 'lock_timeout',\n 'price_changed',\n 'pricing_fact_in_use',\n 'insufficient_stock',\n 'credit_insufficient',\n 'reservation_conflict',\n 'stock_lock_unavailable',\n 'variant_not_found',\n 'variant_stock_write_failed',\n 'stock_invariant_violation',\n 'payment_confirmation_in_flight',\n 'checkout_reservation_release_requires_transaction',\n 'admission_metadata_invalid',\n 'admission_metadata_required',\n 'admission_not_eligible',\n 'admission_eligibility_unavailable',\n 'admission_authority_unavailable',\n 'admission_customer_binding_required',\n 'admission_eligibility_unproven',\n 'capacity_exceeded',\n 'admission_required',\n 'occurrence_lock_unavailable',\n 'occurrence_not_open',\n 'admission_type_capacity_exceeded',\n 'admission_type_occurrence_mismatch',\n 'admission_hold_expired',\n 'admission_hold_checkout_item_conflict',\n 'admission_hold_checkout_conflict',\n 'admission_hold_quantity_mismatch',\n 'admission_hold_unbound',\n 'admission_hold_missing',\n 'admission_hold_checkout_item_missing',\n 'admission_hold_expiry_failed',\n 'admission_hold_expiry_requires_transaction',\n 'admission_hold_line_item_mismatch',\n 'admission_materialization_failed',\n 'variant_inactive',\n 'variant_product_mismatch',\n 'product_not_public',\n 'product_not_eligible',\n 'purchase_limit_exceeded',\n 'market_not_found',\n 'market_shipping_currency_unsupported',\n 'missing_market_rate',\n 'missing_shipping_amount',\n 'no_enabled_payment_provider',\n 'product_market_unavailable',\n 'unsupported_currency',\n 'missing_price_row',\n 'payment_provider_currency_unsupported',\n 'discount_code_not_found',\n 'discount_not_started',\n 'discount_expired',\n 'discount_usage_limit',\n 'discount_per_customer_limit',\n 'discount_customer_required',\n 'discount_first_order_only',\n 'discount_customer_not_eligible',\n 'discount_customer_excluded',\n 'discount_items_required',\n 'discount_product_not_eligible',\n 'discount_product_excluded',\n 'discount_min_order_amount',\n 'discount_currency_scope_required',\n 'discount_allocation_method_unsupported',\n 'currency_mismatch',\n 'customer_token_required',\n 'market_required',\n 'server_derived',\n 'internal_error',\n] as const\n\nexport type CommerceErrorCode = (typeof COMMERCE_ERROR_CODES)[number]\n\ntype CommerceSDKErrorBase = SDKError & {\n readonly kind: 'commerce'\n readonly requestId: string\n readonly retryable: boolean\n readonly retryAfter?: number\n readonly details?: Record<string, unknown>\n}\n\nexport type CommerceSDKError = CommerceSDKErrorBase &\n (\n | { readonly reason: CommerceErrorCode; readonly rawReason?: never }\n | {\n readonly reason: 'unknown_commerce_error'\n readonly rawReason: string\n }\n )\n\nconst COMMERCE_ERROR_CODE_SET: ReadonlySet<string> = new Set(\n COMMERCE_ERROR_CODES,\n)\nconst COMMERCE_ERROR_ENVELOPE_KEYS = new Set([\n 'error',\n 'reason',\n 'requestId',\n 'retryable',\n 'details',\n])\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nexport type CommerceErrorEnvelope = {\n error: string\n reason: string\n requestId: string\n retryable: boolean\n details?: Record<string, unknown>\n}\n\nfunction commerceProtocolError(\n issue: string,\n trustedRequestId?: string,\n): SDKError {\n return createApiError(\n 'Invalid canonical commerce error response.',\n 502,\n { protocol: 'commerce-error-envelope', issue },\n 'The server returned an incompatible commerce error response.',\n 'Verify that the Console commerce contract is deployed before using this SDK version.',\n trustedRequestId,\n )\n}\n\n/** @internal Strictly parse a canonical commerce error without retaining its raw body. */\nexport function parseCommerceErrorEnvelope(\n body: unknown,\n headerRequestId?: string,\n): CommerceErrorEnvelope {\n if (headerRequestId === undefined) {\n throw commerceProtocolError('missing_request_id_header')\n }\n if (headerRequestId.length === 0) {\n throw commerceProtocolError('empty_request_id_header')\n }\n if (!isPlainRecord(body)) {\n throw commerceProtocolError('expected_object', headerRequestId)\n }\n if (Object.keys(body).some((key) => !COMMERCE_ERROR_ENVELOPE_KEYS.has(key))) {\n throw commerceProtocolError('unexpected_field', headerRequestId)\n }\n if (\n typeof body.error !== 'string' ||\n body.error.length === 0 ||\n typeof body.reason !== 'string' ||\n body.reason.length === 0 ||\n typeof body.requestId !== 'string' ||\n body.requestId.length === 0 ||\n (body.retryable !== undefined && typeof body.retryable !== 'boolean') ||\n (body.details !== undefined && !isPlainRecord(body.details))\n ) {\n throw commerceProtocolError('invalid_field', headerRequestId)\n }\n\n if (headerRequestId !== undefined && headerRequestId !== body.requestId) {\n throw commerceProtocolError('request_id_mismatch', headerRequestId)\n }\n\n return {\n error: body.error,\n reason: body.reason,\n requestId: body.requestId,\n retryable: body.retryable === true,\n ...(body.details === undefined ? {} : { details: body.details }),\n }\n}\n\n/** @internal Validate and apply the canonical commerce error envelope. */\nexport function enhanceCommerceError(\n error: SDKError,\n body: unknown,\n headerRequestId?: string,\n): SDKError {\n const envelope = parseCommerceErrorEnvelope(body, headerRequestId)\n\n const known = COMMERCE_ERROR_CODE_SET.has(envelope.reason)\n Object.assign(error, {\n code: envelope.reason,\n kind: 'commerce' as const,\n reason: known\n ? (envelope.reason as CommerceErrorCode)\n : 'unknown_commerce_error',\n ...(known ? {} : { rawReason: envelope.reason }),\n requestId: envelope.requestId,\n retryable: envelope.retryable,\n details: envelope.details,\n })\n return error\n}\n\n/** @internal Apply a non-commerce reason without canonical-commerce validation. */\nexport function enhanceNonCommerceError(\n error: SDKError,\n reason: unknown,\n): SDKError {\n if (typeof reason === 'string') Object.assign(error, { apiReason: reason })\n return error\n}\n\n/**\n * Read the server-provided machine reason across strict commerce and\n * non-commerce SDK errors. Unknown commerce reasons are returned verbatim.\n */\nexport function getSDKErrorReason(error: SDKError): string | undefined {\n if (error.kind !== 'commerce') return error.apiReason\n return error.reason === 'unknown_commerce_error'\n ? error.rawReason\n : error.reason\n}\n\nexport function isCommerceSDKError(error: unknown): error is CommerceSDKError {\n if (!isSDKError(error) || error.kind !== 'commerce') return false\n if (\n typeof error.requestId !== 'string' ||\n typeof error.retryable !== 'boolean' ||\n (error.retryAfter !== undefined &&\n (!Number.isSafeInteger(error.retryAfter) || error.retryAfter < 0)) ||\n typeof error.reason !== 'string'\n ) {\n return false\n }\n return error.reason === 'unknown_commerce_error'\n ? typeof error.rawReason === 'string'\n : COMMERCE_ERROR_CODE_SET.has(error.reason) && error.rawReason === undefined\n}\n\nexport class NetworkError extends SDKError {\n constructor(\n message: string,\n status?: number,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n ) {\n super('NETWORK_ERROR', message, status, details, userMessage, suggestion)\n this.name = 'NetworkError'\n defineSDKErrorType(this, 'NetworkError')\n }\n}\n\nexport class ValidationError extends SDKError {\n constructor(\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n status = 400,\n ) {\n super('VALIDATION_ERROR', message, status, details, userMessage, suggestion)\n this.name = 'ValidationError'\n defineSDKErrorType(this, 'ValidationError')\n }\n}\n\nexport class ApiError extends SDKError {\n constructor(\n message: string,\n status: number,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n ) {\n super(\n 'API_ERROR',\n message,\n status,\n details,\n userMessage,\n suggestion,\n requestId,\n )\n this.name = 'ApiError'\n defineSDKErrorType(this, 'ApiError')\n }\n}\n\nexport class ConfigError extends SDKError {\n constructor(\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n ) {\n super('CONFIG_ERROR', message, undefined, details, userMessage, suggestion)\n this.name = 'ConfigError'\n defineSDKErrorType(this, 'ConfigError')\n }\n}\n\nexport class TimeoutError extends SDKError {\n constructor(\n message = 'Request timed out.',\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n ) {\n super('TIMEOUT_ERROR', message, 408, details, userMessage, suggestion)\n this.name = 'TimeoutError'\n defineSDKErrorType(this, 'TimeoutError')\n }\n}\n\nexport class GoneError extends SDKError {\n constructor(\n message = 'The requested resource is no longer available.',\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n ) {\n super('GONE_ERROR', message, 410, details, userMessage, suggestion)\n this.name = 'GoneError'\n defineSDKErrorType(this, 'GoneError')\n }\n}\n\nexport class ServiceUnavailableError extends SDKError {\n readonly retryAfter?: number\n\n constructor(\n message = 'Service temporarily unavailable.',\n retryAfter?: number,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n ) {\n super(\n 'SERVICE_UNAVAILABLE_ERROR',\n message,\n 503,\n details,\n userMessage,\n suggestion,\n )\n this.name = 'ServiceUnavailableError'\n this.retryAfter = retryAfter\n defineSDKErrorType(this, 'ServiceUnavailableError')\n }\n}\n\nexport class UsageLimitError extends SDKError {\n readonly usage: { limit: number; current: number; remaining: number }\n\n constructor(\n message: string,\n usage: { limit: number; current: number; remaining: number },\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n ) {\n super('USAGE_LIMIT_ERROR', message, 429, details, userMessage, suggestion)\n this.name = 'UsageLimitError'\n this.usage = usage\n defineSDKErrorType(this, 'UsageLimitError')\n }\n\n toJSON() {\n return {\n ...super.toJSON(),\n usage: this.usage,\n }\n }\n}\n\nexport class AuthError extends SDKError {\n constructor(\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n ) {\n super(\n 'auth_error',\n message,\n 401,\n details,\n userMessage,\n suggestion,\n requestId,\n )\n this.name = 'AuthError'\n defineSDKErrorType(this, 'AuthError')\n }\n}\n\nexport class PermissionError extends SDKError {\n constructor(\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n ) {\n super(\n 'permission_error',\n message,\n 403,\n details,\n userMessage,\n suggestion,\n requestId,\n )\n this.name = 'PermissionError'\n defineSDKErrorType(this, 'PermissionError')\n }\n}\n\nexport class NotFoundError extends SDKError {\n constructor(\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n ) {\n super(\n 'not_found',\n message,\n 404,\n details,\n userMessage,\n suggestion,\n requestId,\n )\n this.name = 'NotFoundError'\n defineSDKErrorType(this, 'NotFoundError')\n }\n}\n\nexport class ConflictError extends SDKError {\n constructor(\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n ) {\n super('conflict', message, 409, details, userMessage, suggestion, requestId)\n this.name = 'ConflictError'\n defineSDKErrorType(this, 'ConflictError')\n }\n}\n\nexport class RateLimitError extends SDKError {\n readonly retryAfter?: number\n\n constructor(\n message: string,\n retryAfter?: number,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n ) {\n super(\n 'rate_limit_exceeded',\n message,\n 429,\n details,\n userMessage,\n suggestion,\n requestId,\n )\n this.name = 'RateLimitError'\n this.retryAfter = retryAfter\n defineSDKErrorType(this, 'RateLimitError')\n }\n}\n\nfunction hasBrandedSDKErrorShape(error: unknown): error is SDKError {\n if (error === null || typeof error !== 'object') return false\n\n const candidate = error as Record<PropertyKey, unknown>\n return (\n candidate[SDK_ERROR_BRAND] === true &&\n typeof candidate.name === 'string' &&\n typeof candidate.code === 'string' &&\n typeof candidate.message === 'string' &&\n (candidate.status === undefined || typeof candidate.status === 'number') &&\n (candidate.userMessage === undefined ||\n typeof candidate.userMessage === 'string') &&\n (candidate.suggestion === undefined ||\n typeof candidate.suggestion === 'string') &&\n (candidate.requestId === undefined ||\n typeof candidate.requestId === 'string') &&\n (candidate.kind === undefined || candidate.kind === 'commerce') &&\n (candidate.reason === undefined || typeof candidate.reason === 'string') &&\n (candidate.rawReason === undefined ||\n typeof candidate.rawReason === 'string') &&\n (candidate.apiReason === undefined ||\n typeof candidate.apiReason === 'string') &&\n (candidate.retryable === undefined ||\n typeof candidate.retryable === 'boolean') &&\n (candidate.retryAfter === undefined ||\n typeof candidate.retryAfter === 'number') &&\n typeof candidate.getUserMessage === 'function' &&\n typeof candidate.toJSON === 'function'\n )\n}\n\nfunction hasSDKErrorType(error: unknown, type: SDKErrorType): boolean {\n return (\n hasBrandedSDKErrorShape(error) &&\n (error as unknown as Record<PropertyKey, unknown>)[SDK_ERROR_TYPE_BRAND] ===\n type\n )\n}\n\nexport function isSDKError(error: unknown): error is SDKError {\n return error instanceof SDKError || hasBrandedSDKErrorShape(error)\n}\n\nexport function isNetworkError(error: unknown): error is NetworkError {\n return error instanceof NetworkError || hasSDKErrorType(error, 'NetworkError')\n}\n\nexport function isValidationError(error: unknown): error is ValidationError {\n if (\n error instanceof ValidationError ||\n hasSDKErrorType(error, 'ValidationError')\n ) {\n return true\n }\n if (error == null || typeof error !== 'object') return false\n\n const candidate = error as {\n code?: unknown\n name?: unknown\n message?: unknown\n getUserMessage?: unknown\n toJSON?: unknown\n }\n return (\n candidate.name === 'ValidationError' &&\n candidate.code === 'VALIDATION_ERROR' &&\n typeof candidate.message === 'string' &&\n typeof candidate.getUserMessage === 'function' &&\n typeof candidate.toJSON === 'function'\n )\n}\n\nexport function isApiError(error: unknown): error is ApiError {\n return error instanceof ApiError || hasSDKErrorType(error, 'ApiError')\n}\n\nexport function isConfigError(error: unknown): error is ConfigError {\n return error instanceof ConfigError || hasSDKErrorType(error, 'ConfigError')\n}\n\nexport function isTimeoutError(error: unknown): error is TimeoutError {\n return error instanceof TimeoutError || hasSDKErrorType(error, 'TimeoutError')\n}\n\nexport function isGoneError(error: unknown): error is GoneError {\n return error instanceof GoneError || hasSDKErrorType(error, 'GoneError')\n}\n\nexport function isServiceUnavailableError(\n error: unknown,\n): error is ServiceUnavailableError {\n return (\n error instanceof ServiceUnavailableError ||\n hasSDKErrorType(error, 'ServiceUnavailableError')\n )\n}\n\nexport function isUsageLimitError(error: unknown): error is UsageLimitError {\n return (\n error instanceof UsageLimitError ||\n hasSDKErrorType(error, 'UsageLimitError')\n )\n}\n\nexport function isAuthError(error: unknown): error is AuthError {\n return error instanceof AuthError || hasSDKErrorType(error, 'AuthError')\n}\n\nexport function isPermissionError(error: unknown): error is PermissionError {\n return (\n error instanceof PermissionError ||\n hasSDKErrorType(error, 'PermissionError')\n )\n}\n\nexport function isNotFoundError(error: unknown): error is NotFoundError {\n return (\n error instanceof NotFoundError || hasSDKErrorType(error, 'NotFoundError')\n )\n}\n\nexport function isConflictError(error: unknown): error is ConflictError {\n return (\n error instanceof ConflictError || hasSDKErrorType(error, 'ConflictError')\n )\n}\n\nexport function isRateLimitError(error: unknown): error is RateLimitError {\n return (\n error instanceof RateLimitError || hasSDKErrorType(error, 'RateLimitError')\n )\n}\n\nexport const createNetworkError = (\n message: string,\n status?: number,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n) => new NetworkError(message, status, details, userMessage, suggestion)\n\nexport const createValidationError = (\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n status?: number,\n) => new ValidationError(message, details, userMessage, suggestion, status)\n\nexport const createApiError = (\n message: string,\n status: number,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n) => new ApiError(message, status, details, userMessage, suggestion, requestId)\n\nexport const createConfigError = (\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n) => new ConfigError(message, details, userMessage, suggestion)\n\nexport const createTimeoutError = (\n message?: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n) => new TimeoutError(message, details, userMessage, suggestion)\n\nexport const createGoneError = (\n message?: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n) => new GoneError(message, details, userMessage, suggestion)\n\nexport const createServiceUnavailableError = (\n message?: string,\n retryAfter?: number,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n) =>\n new ServiceUnavailableError(\n message,\n retryAfter,\n details,\n userMessage,\n suggestion,\n )\n\nexport const createUsageLimitError = (\n message: string,\n usage: { limit: number; current: number; remaining: number },\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n) => new UsageLimitError(message, usage, details, userMessage, suggestion)\n\nexport const createAuthError = (\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n) => new AuthError(message, details, userMessage, suggestion, requestId)\n\nexport const createPermissionError = (\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n) => new PermissionError(message, details, userMessage, suggestion, requestId)\n\nexport const createNotFoundError = (\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n) => new NotFoundError(message, details, userMessage, suggestion, requestId)\n\nexport const createConflictError = (\n message: string,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n) => new ConflictError(message, details, userMessage, suggestion, requestId)\n\nexport const createRateLimitError = (\n message: string,\n retryAfter?: number,\n details?: unknown,\n userMessage?: string,\n suggestion?: string,\n requestId?: string,\n) =>\n new RateLimitError(\n message,\n retryAfter,\n details,\n userMessage,\n suggestion,\n requestId,\n )\n","import { createValidationError } from '../core/internal/errors'\n\n/** v2 purpose separation must also fail the original v1 verifier's audience check. */\nexport const EMBEDDED_ADMIN_EXECUTION_AUDIENCE_PREFIX =\n 'urn:01-software:embedded-admin-execution:' as const\n\nexport const EMBEDDED_ADMIN_ACTION_PROTOCOL_VERSION = 2 as const\nexport const EMBEDDED_ADMIN_ACTION_CAPABILITY = 'collection-actions' as const\nexport const EMBEDDED_ADMIN_MAX_ACTIONS = 20\nexport const EMBEDDED_ADMIN_MAX_SELECTED_IDS = 100\n\nexport type EmbeddedAdminAction = {\n id: string\n label: string\n collection: string\n requiresSelection: boolean\n}\n\nexport type EmbeddedAdminExecutionContext = {\n executionId: string\n expiresAt: number\n actionId: string\n collection: string\n selectedIds: string[]\n}\n\nconst ACTION_ID = /^[a-z][a-z0-9_-]{0,63}$/\nconst COLLECTION = /^[a-z][a-z0-9-]{0,63}$/\nconst EXECUTION_ID =\n /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/\n\nfunction recordWithKeys(\n value: unknown,\n keys: string[],\n): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw createValidationError('Invalid embedded admin action context.')\n }\n const record = value as Record<string, unknown>\n if (Object.keys(record).some((key) => !keys.includes(key))) {\n throw createValidationError('Invalid embedded admin action context.')\n }\n return record\n}\n\nexport function normalizeEmbeddedAdminActions(\n value: unknown,\n): EmbeddedAdminAction[] {\n if (value === undefined || value === null) return []\n if (!Array.isArray(value) || value.length > EMBEDDED_ADMIN_MAX_ACTIONS) {\n throw createValidationError('Invalid embedded admin actions.')\n }\n const ids = new Set<string>()\n return value.map((value) => {\n const action = recordWithKeys(value, [\n 'id',\n 'label',\n 'collection',\n 'requiresSelection',\n ])\n if (\n typeof action.id !== 'string' ||\n !ACTION_ID.test(action.id) ||\n ids.has(action.id) ||\n typeof action.label !== 'string' ||\n !action.label.trim() ||\n action.label.trim().length > 80 ||\n typeof action.collection !== 'string' ||\n !COLLECTION.test(action.collection) ||\n typeof action.requiresSelection !== 'boolean'\n )\n throw createValidationError(\n 'Invalid embedded admin action configuration.',\n )\n ids.add(action.id)\n return {\n id: action.id,\n label: action.label.trim(),\n collection: action.collection,\n requiresSelection: action.requiresSelection,\n }\n })\n}\n\nexport function normalizeEmbeddedAdminExecutionContext(\n value: unknown,\n): EmbeddedAdminExecutionContext {\n const input = recordWithKeys(value, [\n 'executionId',\n 'expiresAt',\n 'actionId',\n 'collection',\n 'selectedIds',\n ])\n if (\n typeof input.executionId !== 'string' ||\n !EXECUTION_ID.test(input.executionId) ||\n typeof input.expiresAt !== 'number' ||\n !Number.isSafeInteger(input.expiresAt) ||\n input.expiresAt <= 0 ||\n typeof input.actionId !== 'string' ||\n !ACTION_ID.test(input.actionId) ||\n typeof input.collection !== 'string' ||\n !COLLECTION.test(input.collection) ||\n !Array.isArray(input.selectedIds) ||\n input.selectedIds.length > EMBEDDED_ADMIN_MAX_SELECTED_IDS ||\n input.selectedIds.some(\n (id) =>\n typeof id !== 'string' ||\n !id ||\n id.length > 128 ||\n id.trim() !== id ||\n Array.from(id).some(\n (character) =>\n character.charCodeAt(0) <= 0x20 || character.charCodeAt(0) === 0x7f,\n ),\n ) ||\n new Set(input.selectedIds).size !== input.selectedIds.length\n )\n throw createValidationError('Invalid embedded admin execution context.')\n return {\n executionId: input.executionId,\n expiresAt: input.expiresAt,\n actionId: input.actionId,\n collection: input.collection,\n selectedIds: [...(input.selectedIds as string[])].sort(),\n }\n}\n\nexport function embeddedAdminExecutionContextsEqual(\n left: unknown,\n right: unknown,\n): boolean {\n try {\n return (\n JSON.stringify(normalizeEmbeddedAdminExecutionContext(left)) ===\n JSON.stringify(normalizeEmbeddedAdminExecutionContext(right))\n )\n } catch {\n return false\n }\n}\n"],"mappings":"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","names":["value","port"]}
|
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
/** v2 purpose separation must also fail the original v1 verifier's audience check. */
|
|
2
|
+
declare const EMBEDDED_ADMIN_EXECUTION_AUDIENCE_PREFIX: "urn:01-software:embedded-admin-execution:";
|
|
3
|
+
declare const EMBEDDED_ADMIN_ACTION_PROTOCOL_VERSION: 2;
|
|
4
|
+
declare const EMBEDDED_ADMIN_ACTION_CAPABILITY: "collection-actions";
|
|
5
|
+
declare const EMBEDDED_ADMIN_MAX_ACTIONS = 20;
|
|
6
|
+
declare const EMBEDDED_ADMIN_MAX_SELECTED_IDS = 100;
|
|
7
|
+
type EmbeddedAdminAction = {
|
|
8
|
+
id: string;
|
|
9
|
+
label: string;
|
|
10
|
+
collection: string;
|
|
11
|
+
requiresSelection: boolean;
|
|
12
|
+
};
|
|
13
|
+
type EmbeddedAdminExecutionContext = {
|
|
14
|
+
executionId: string;
|
|
15
|
+
expiresAt: number;
|
|
16
|
+
actionId: string;
|
|
17
|
+
collection: string;
|
|
18
|
+
selectedIds: string[];
|
|
19
|
+
};
|
|
20
|
+
declare function normalizeEmbeddedAdminActions(value: unknown): EmbeddedAdminAction[];
|
|
21
|
+
declare function normalizeEmbeddedAdminExecutionContext(value: unknown): EmbeddedAdminExecutionContext;
|
|
22
|
+
declare function embeddedAdminExecutionContextsEqual(left: unknown, right: unknown): boolean;
|
|
23
|
+
|
|
1
24
|
declare const EMBEDDED_ADMIN_PROTOCOL_VERSION: 1;
|
|
2
25
|
declare const EMBEDDED_ADMIN_CHALLENGE_MESSAGE: "01.embedded-admin.challenge";
|
|
3
26
|
declare const EMBEDDED_ADMIN_READY_MESSAGE: "01.embedded-admin.ready";
|
|
@@ -26,16 +49,22 @@ type EmbeddedAdminTenantRole = (typeof EMBEDDED_ADMIN_TENANT_ROLES)[number];
|
|
|
26
49
|
/** Missing legacy settings retain administrator-only execution; invalid settings fail closed. */
|
|
27
50
|
declare function normalizeEmbeddedAdminAllowedRoles(value: unknown): EmbeddedAdminTenantRole[] | null;
|
|
28
51
|
type EmbeddedAdminBindingConfiguration = {
|
|
52
|
+
/** Explicit opt-in; missing values keep sandbox downloads disabled. */
|
|
53
|
+
allowDownloads?: boolean;
|
|
29
54
|
allowedRoles?: EmbeddedAdminTenantRole[];
|
|
30
55
|
enabled: boolean;
|
|
31
56
|
label: string;
|
|
32
57
|
origin: string;
|
|
33
58
|
path: string;
|
|
59
|
+
actions?: EmbeddedAdminAction[];
|
|
34
60
|
};
|
|
35
61
|
type EmbeddedAdminSessionReceipt = {
|
|
36
62
|
requestId: string;
|
|
37
63
|
token: string;
|
|
38
64
|
};
|
|
65
|
+
type EmbeddedAdminExecutionReceipt = EmbeddedAdminSessionReceipt & {
|
|
66
|
+
execution: EmbeddedAdminExecutionContext;
|
|
67
|
+
};
|
|
39
68
|
type ReceiveEmbeddedAdminSessionOptions = {
|
|
40
69
|
/** Test fixtures only. Production integrations must keep HTTPS enforcement. */
|
|
41
70
|
allowLoopbackHttp?: boolean;
|
|
@@ -53,7 +82,9 @@ declare function normalizeEmbeddedAdminRelativePath(value: unknown): string | nu
|
|
|
53
82
|
declare function normalizeEmbeddedAdminBindingConfiguration(value: unknown, options?: {
|
|
54
83
|
allowLoopbackConsoleHttp?: boolean;
|
|
55
84
|
consoleOrigin?: string;
|
|
56
|
-
}): EmbeddedAdminBindingConfiguration
|
|
85
|
+
}): EmbeddedAdminBindingConfiguration & {
|
|
86
|
+
allowDownloads: boolean;
|
|
87
|
+
};
|
|
57
88
|
declare function isEmbeddedAdminChallengeMessage(value: unknown): value is EmbeddedAdminChallengeMessage;
|
|
58
89
|
declare function isEmbeddedAdminReadyMessage(value: unknown): value is EmbeddedAdminReadyMessage;
|
|
59
90
|
declare function isEmbeddedAdminSessionMessage(value: unknown): value is EmbeddedAdminSessionMessage;
|
|
@@ -63,5 +94,7 @@ declare function isEmbeddedAdminSessionMessage(value: unknown): value is Embedde
|
|
|
63
94
|
* never persist, log, decode, or use it as Console API authority in-browser.
|
|
64
95
|
*/
|
|
65
96
|
declare function receiveEmbeddedAdminSession(options: ReceiveEmbeddedAdminSessionOptions): Promise<EmbeddedAdminSessionReceipt>;
|
|
97
|
+
/** Receives a v2 action only. It never silently accepts an identity-only launch. */
|
|
98
|
+
declare function receiveEmbeddedAdminExecution(options: ReceiveEmbeddedAdminSessionOptions): Promise<EmbeddedAdminExecutionReceipt>;
|
|
66
99
|
|
|
67
|
-
export { EMBEDDED_ADMIN_APP_KEY, EMBEDDED_ADMIN_CHALLENGE_MESSAGE, EMBEDDED_ADMIN_PROTOCOL_VERSION, EMBEDDED_ADMIN_READY_MESSAGE, EMBEDDED_ADMIN_SESSION_MESSAGE, EMBEDDED_ADMIN_SESSION_TTL_SECONDS, EMBEDDED_ADMIN_TENANT_ROLES, type EmbeddedAdminBindingConfiguration, type EmbeddedAdminChallengeMessage, type EmbeddedAdminReadyMessage, type EmbeddedAdminSessionMessage, type EmbeddedAdminSessionReceipt, type EmbeddedAdminTenantRole, type ReceiveEmbeddedAdminSessionOptions, isEmbeddedAdminChallengeMessage, isEmbeddedAdminReadyMessage, isEmbeddedAdminSessionMessage, normalizeEmbeddedAdminAllowedRoles, normalizeEmbeddedAdminBindingConfiguration, normalizeEmbeddedAdminExactOrigin, normalizeEmbeddedAdminRelativePath, receiveEmbeddedAdminSession };
|
|
100
|
+
export { EMBEDDED_ADMIN_ACTION_CAPABILITY, EMBEDDED_ADMIN_ACTION_PROTOCOL_VERSION, EMBEDDED_ADMIN_APP_KEY, EMBEDDED_ADMIN_CHALLENGE_MESSAGE, EMBEDDED_ADMIN_EXECUTION_AUDIENCE_PREFIX, EMBEDDED_ADMIN_MAX_ACTIONS, EMBEDDED_ADMIN_MAX_SELECTED_IDS, EMBEDDED_ADMIN_PROTOCOL_VERSION, EMBEDDED_ADMIN_READY_MESSAGE, EMBEDDED_ADMIN_SESSION_MESSAGE, EMBEDDED_ADMIN_SESSION_TTL_SECONDS, EMBEDDED_ADMIN_TENANT_ROLES, type EmbeddedAdminAction, type EmbeddedAdminBindingConfiguration, type EmbeddedAdminChallengeMessage, type EmbeddedAdminExecutionContext, type EmbeddedAdminExecutionReceipt, type EmbeddedAdminReadyMessage, type EmbeddedAdminSessionMessage, type EmbeddedAdminSessionReceipt, type EmbeddedAdminTenantRole, type ReceiveEmbeddedAdminSessionOptions, embeddedAdminExecutionContextsEqual, isEmbeddedAdminChallengeMessage, isEmbeddedAdminReadyMessage, isEmbeddedAdminSessionMessage, normalizeEmbeddedAdminActions, normalizeEmbeddedAdminAllowedRoles, normalizeEmbeddedAdminBindingConfiguration, normalizeEmbeddedAdminExactOrigin, normalizeEmbeddedAdminExecutionContext, normalizeEmbeddedAdminRelativePath, receiveEmbeddedAdminExecution, receiveEmbeddedAdminSession };
|
package/dist/embedded-admin.d.ts
CHANGED
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
/** v2 purpose separation must also fail the original v1 verifier's audience check. */
|
|
2
|
+
declare const EMBEDDED_ADMIN_EXECUTION_AUDIENCE_PREFIX: "urn:01-software:embedded-admin-execution:";
|
|
3
|
+
declare const EMBEDDED_ADMIN_ACTION_PROTOCOL_VERSION: 2;
|
|
4
|
+
declare const EMBEDDED_ADMIN_ACTION_CAPABILITY: "collection-actions";
|
|
5
|
+
declare const EMBEDDED_ADMIN_MAX_ACTIONS = 20;
|
|
6
|
+
declare const EMBEDDED_ADMIN_MAX_SELECTED_IDS = 100;
|
|
7
|
+
type EmbeddedAdminAction = {
|
|
8
|
+
id: string;
|
|
9
|
+
label: string;
|
|
10
|
+
collection: string;
|
|
11
|
+
requiresSelection: boolean;
|
|
12
|
+
};
|
|
13
|
+
type EmbeddedAdminExecutionContext = {
|
|
14
|
+
executionId: string;
|
|
15
|
+
expiresAt: number;
|
|
16
|
+
actionId: string;
|
|
17
|
+
collection: string;
|
|
18
|
+
selectedIds: string[];
|
|
19
|
+
};
|
|
20
|
+
declare function normalizeEmbeddedAdminActions(value: unknown): EmbeddedAdminAction[];
|
|
21
|
+
declare function normalizeEmbeddedAdminExecutionContext(value: unknown): EmbeddedAdminExecutionContext;
|
|
22
|
+
declare function embeddedAdminExecutionContextsEqual(left: unknown, right: unknown): boolean;
|
|
23
|
+
|
|
1
24
|
declare const EMBEDDED_ADMIN_PROTOCOL_VERSION: 1;
|
|
2
25
|
declare const EMBEDDED_ADMIN_CHALLENGE_MESSAGE: "01.embedded-admin.challenge";
|
|
3
26
|
declare const EMBEDDED_ADMIN_READY_MESSAGE: "01.embedded-admin.ready";
|
|
@@ -26,16 +49,22 @@ type EmbeddedAdminTenantRole = (typeof EMBEDDED_ADMIN_TENANT_ROLES)[number];
|
|
|
26
49
|
/** Missing legacy settings retain administrator-only execution; invalid settings fail closed. */
|
|
27
50
|
declare function normalizeEmbeddedAdminAllowedRoles(value: unknown): EmbeddedAdminTenantRole[] | null;
|
|
28
51
|
type EmbeddedAdminBindingConfiguration = {
|
|
52
|
+
/** Explicit opt-in; missing values keep sandbox downloads disabled. */
|
|
53
|
+
allowDownloads?: boolean;
|
|
29
54
|
allowedRoles?: EmbeddedAdminTenantRole[];
|
|
30
55
|
enabled: boolean;
|
|
31
56
|
label: string;
|
|
32
57
|
origin: string;
|
|
33
58
|
path: string;
|
|
59
|
+
actions?: EmbeddedAdminAction[];
|
|
34
60
|
};
|
|
35
61
|
type EmbeddedAdminSessionReceipt = {
|
|
36
62
|
requestId: string;
|
|
37
63
|
token: string;
|
|
38
64
|
};
|
|
65
|
+
type EmbeddedAdminExecutionReceipt = EmbeddedAdminSessionReceipt & {
|
|
66
|
+
execution: EmbeddedAdminExecutionContext;
|
|
67
|
+
};
|
|
39
68
|
type ReceiveEmbeddedAdminSessionOptions = {
|
|
40
69
|
/** Test fixtures only. Production integrations must keep HTTPS enforcement. */
|
|
41
70
|
allowLoopbackHttp?: boolean;
|
|
@@ -53,7 +82,9 @@ declare function normalizeEmbeddedAdminRelativePath(value: unknown): string | nu
|
|
|
53
82
|
declare function normalizeEmbeddedAdminBindingConfiguration(value: unknown, options?: {
|
|
54
83
|
allowLoopbackConsoleHttp?: boolean;
|
|
55
84
|
consoleOrigin?: string;
|
|
56
|
-
}): EmbeddedAdminBindingConfiguration
|
|
85
|
+
}): EmbeddedAdminBindingConfiguration & {
|
|
86
|
+
allowDownloads: boolean;
|
|
87
|
+
};
|
|
57
88
|
declare function isEmbeddedAdminChallengeMessage(value: unknown): value is EmbeddedAdminChallengeMessage;
|
|
58
89
|
declare function isEmbeddedAdminReadyMessage(value: unknown): value is EmbeddedAdminReadyMessage;
|
|
59
90
|
declare function isEmbeddedAdminSessionMessage(value: unknown): value is EmbeddedAdminSessionMessage;
|
|
@@ -63,5 +94,7 @@ declare function isEmbeddedAdminSessionMessage(value: unknown): value is Embedde
|
|
|
63
94
|
* never persist, log, decode, or use it as Console API authority in-browser.
|
|
64
95
|
*/
|
|
65
96
|
declare function receiveEmbeddedAdminSession(options: ReceiveEmbeddedAdminSessionOptions): Promise<EmbeddedAdminSessionReceipt>;
|
|
97
|
+
/** Receives a v2 action only. It never silently accepts an identity-only launch. */
|
|
98
|
+
declare function receiveEmbeddedAdminExecution(options: ReceiveEmbeddedAdminSessionOptions): Promise<EmbeddedAdminExecutionReceipt>;
|
|
66
99
|
|
|
67
|
-
export { EMBEDDED_ADMIN_APP_KEY, EMBEDDED_ADMIN_CHALLENGE_MESSAGE, EMBEDDED_ADMIN_PROTOCOL_VERSION, EMBEDDED_ADMIN_READY_MESSAGE, EMBEDDED_ADMIN_SESSION_MESSAGE, EMBEDDED_ADMIN_SESSION_TTL_SECONDS, EMBEDDED_ADMIN_TENANT_ROLES, type EmbeddedAdminBindingConfiguration, type EmbeddedAdminChallengeMessage, type EmbeddedAdminReadyMessage, type EmbeddedAdminSessionMessage, type EmbeddedAdminSessionReceipt, type EmbeddedAdminTenantRole, type ReceiveEmbeddedAdminSessionOptions, isEmbeddedAdminChallengeMessage, isEmbeddedAdminReadyMessage, isEmbeddedAdminSessionMessage, normalizeEmbeddedAdminAllowedRoles, normalizeEmbeddedAdminBindingConfiguration, normalizeEmbeddedAdminExactOrigin, normalizeEmbeddedAdminRelativePath, receiveEmbeddedAdminSession };
|
|
100
|
+
export { EMBEDDED_ADMIN_ACTION_CAPABILITY, EMBEDDED_ADMIN_ACTION_PROTOCOL_VERSION, EMBEDDED_ADMIN_APP_KEY, EMBEDDED_ADMIN_CHALLENGE_MESSAGE, EMBEDDED_ADMIN_EXECUTION_AUDIENCE_PREFIX, EMBEDDED_ADMIN_MAX_ACTIONS, EMBEDDED_ADMIN_MAX_SELECTED_IDS, EMBEDDED_ADMIN_PROTOCOL_VERSION, EMBEDDED_ADMIN_READY_MESSAGE, EMBEDDED_ADMIN_SESSION_MESSAGE, EMBEDDED_ADMIN_SESSION_TTL_SECONDS, EMBEDDED_ADMIN_TENANT_ROLES, type EmbeddedAdminAction, type EmbeddedAdminBindingConfiguration, type EmbeddedAdminChallengeMessage, type EmbeddedAdminExecutionContext, type EmbeddedAdminExecutionReceipt, type EmbeddedAdminReadyMessage, type EmbeddedAdminSessionMessage, type EmbeddedAdminSessionReceipt, type EmbeddedAdminTenantRole, type ReceiveEmbeddedAdminSessionOptions, embeddedAdminExecutionContextsEqual, isEmbeddedAdminChallengeMessage, isEmbeddedAdminReadyMessage, isEmbeddedAdminSessionMessage, normalizeEmbeddedAdminActions, normalizeEmbeddedAdminAllowedRoles, normalizeEmbeddedAdminBindingConfiguration, normalizeEmbeddedAdminExactOrigin, normalizeEmbeddedAdminExecutionContext, normalizeEmbeddedAdminRelativePath, receiveEmbeddedAdminExecution, receiveEmbeddedAdminSession };
|
package/dist/embedded-admin.js
CHANGED
|
@@ -85,6 +85,7 @@ var COMMERCE_ERROR_CODES = [
|
|
|
85
85
|
"cart_not_active",
|
|
86
86
|
"cart_locked",
|
|
87
87
|
"cart_empty",
|
|
88
|
+
"shipping_address_required",
|
|
88
89
|
"cart_market_unavailable",
|
|
89
90
|
"cart_market_mismatch",
|
|
90
91
|
"checkout_not_open",
|
|
@@ -101,6 +102,7 @@ var COMMERCE_ERROR_CODES = [
|
|
|
101
102
|
"price_changed",
|
|
102
103
|
"pricing_fact_in_use",
|
|
103
104
|
"insufficient_stock",
|
|
105
|
+
"credit_insufficient",
|
|
104
106
|
"reservation_conflict",
|
|
105
107
|
"stock_lock_unavailable",
|
|
106
108
|
"variant_not_found",
|
|
@@ -179,6 +181,81 @@ var ValidationError = class extends SDKError {
|
|
|
179
181
|
};
|
|
180
182
|
var createValidationError = (message, details, userMessage, suggestion, status) => new ValidationError(message, details, userMessage, suggestion, status);
|
|
181
183
|
|
|
184
|
+
// src/embedded-admin/actions.ts
|
|
185
|
+
var EMBEDDED_ADMIN_EXECUTION_AUDIENCE_PREFIX = "urn:01-software:embedded-admin-execution:";
|
|
186
|
+
var EMBEDDED_ADMIN_ACTION_PROTOCOL_VERSION = 2;
|
|
187
|
+
var EMBEDDED_ADMIN_ACTION_CAPABILITY = "collection-actions";
|
|
188
|
+
var EMBEDDED_ADMIN_MAX_ACTIONS = 20;
|
|
189
|
+
var EMBEDDED_ADMIN_MAX_SELECTED_IDS = 100;
|
|
190
|
+
var ACTION_ID = /^[a-z][a-z0-9_-]{0,63}$/;
|
|
191
|
+
var COLLECTION = /^[a-z][a-z0-9-]{0,63}$/;
|
|
192
|
+
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}$/;
|
|
193
|
+
function recordWithKeys(value, keys) {
|
|
194
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
195
|
+
throw createValidationError("Invalid embedded admin action context.");
|
|
196
|
+
}
|
|
197
|
+
const record = value;
|
|
198
|
+
if (Object.keys(record).some((key) => !keys.includes(key))) {
|
|
199
|
+
throw createValidationError("Invalid embedded admin action context.");
|
|
200
|
+
}
|
|
201
|
+
return record;
|
|
202
|
+
}
|
|
203
|
+
function normalizeEmbeddedAdminActions(value) {
|
|
204
|
+
if (value === void 0 || value === null) return [];
|
|
205
|
+
if (!Array.isArray(value) || value.length > EMBEDDED_ADMIN_MAX_ACTIONS) {
|
|
206
|
+
throw createValidationError("Invalid embedded admin actions.");
|
|
207
|
+
}
|
|
208
|
+
const ids = /* @__PURE__ */ new Set();
|
|
209
|
+
return value.map((value2) => {
|
|
210
|
+
const action = recordWithKeys(value2, [
|
|
211
|
+
"id",
|
|
212
|
+
"label",
|
|
213
|
+
"collection",
|
|
214
|
+
"requiresSelection"
|
|
215
|
+
]);
|
|
216
|
+
if (typeof action.id !== "string" || !ACTION_ID.test(action.id) || ids.has(action.id) || typeof action.label !== "string" || !action.label.trim() || action.label.trim().length > 80 || typeof action.collection !== "string" || !COLLECTION.test(action.collection) || typeof action.requiresSelection !== "boolean")
|
|
217
|
+
throw createValidationError(
|
|
218
|
+
"Invalid embedded admin action configuration."
|
|
219
|
+
);
|
|
220
|
+
ids.add(action.id);
|
|
221
|
+
return {
|
|
222
|
+
id: action.id,
|
|
223
|
+
label: action.label.trim(),
|
|
224
|
+
collection: action.collection,
|
|
225
|
+
requiresSelection: action.requiresSelection
|
|
226
|
+
};
|
|
227
|
+
});
|
|
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
|
+
|
|
182
259
|
// src/embedded-admin/index.ts
|
|
183
260
|
var EMBEDDED_ADMIN_PROTOCOL_VERSION = 1;
|
|
184
261
|
var EMBEDDED_ADMIN_CHALLENGE_MESSAGE = "01.embedded-admin.challenge";
|
|
@@ -244,6 +321,9 @@ function normalizeEmbeddedAdminBindingConfiguration(value, options = {}) {
|
|
|
244
321
|
throw createValidationError("Embedded admin binding must be an object.");
|
|
245
322
|
}
|
|
246
323
|
const input = value;
|
|
324
|
+
if (input.allowDownloads !== void 0 && typeof input.allowDownloads !== "boolean") {
|
|
325
|
+
throw createValidationError("allowDownloads must be a boolean.");
|
|
326
|
+
}
|
|
247
327
|
const allowedRoles = normalizeEmbeddedAdminAllowedRoles(input.allowedRoles);
|
|
248
328
|
if (!allowedRoles)
|
|
249
329
|
throw createValidationError(
|
|
@@ -278,9 +358,11 @@ function normalizeEmbeddedAdminBindingConfiguration(value, options = {}) {
|
|
|
278
358
|
return {
|
|
279
359
|
allowedRoles,
|
|
280
360
|
enabled: input.enabled !== false,
|
|
361
|
+
allowDownloads: input.allowDownloads === true,
|
|
281
362
|
label,
|
|
282
363
|
origin,
|
|
283
|
-
path
|
|
364
|
+
path,
|
|
365
|
+
...input.actions === void 0 ? {} : { actions: normalizeEmbeddedAdminActions(input.actions) }
|
|
284
366
|
};
|
|
285
367
|
}
|
|
286
368
|
function isEmbeddedAdminChallengeMessage(value) {
|
|
@@ -299,6 +381,12 @@ function isEmbeddedAdminSessionMessage(value) {
|
|
|
299
381
|
return message.type === EMBEDDED_ADMIN_SESSION_MESSAGE && message.version === EMBEDDED_ADMIN_PROTOCOL_VERSION && typeof message.requestId === "string" && message.requestId.length >= 16 && message.requestId.length <= 128 && typeof message.token === "string" && message.token.length > 0;
|
|
300
382
|
}
|
|
301
383
|
function receiveEmbeddedAdminSession(options) {
|
|
384
|
+
return receiveSession(options, false);
|
|
385
|
+
}
|
|
386
|
+
function receiveEmbeddedAdminExecution(options) {
|
|
387
|
+
return receiveSession(options, true);
|
|
388
|
+
}
|
|
389
|
+
function receiveSession(options, action) {
|
|
302
390
|
if (typeof window === "undefined" || window.parent === window) {
|
|
303
391
|
return Promise.reject(
|
|
304
392
|
createValidationError(
|
|
@@ -350,13 +438,43 @@ function receiveEmbeddedAdminSession(options) {
|
|
|
350
438
|
};
|
|
351
439
|
const abort = () => fail(new Error("Embedded admin session receipt aborted."));
|
|
352
440
|
const acceptSession = (event, expectedRequestId) => {
|
|
353
|
-
if (
|
|
354
|
-
|
|
441
|
+
if (action) {
|
|
442
|
+
const message = event.data;
|
|
443
|
+
if (!message || message.type !== EMBEDDED_ADMIN_SESSION_MESSAGE || message.version !== EMBEDDED_ADMIN_ACTION_PROTOCOL_VERSION || message.requestId !== expectedRequestId || typeof message.token !== "string" || !message.token)
|
|
444
|
+
return;
|
|
445
|
+
try {
|
|
446
|
+
finish({
|
|
447
|
+
requestId: expectedRequestId,
|
|
448
|
+
token: message.token,
|
|
449
|
+
execution: normalizeEmbeddedAdminExecutionContext(
|
|
450
|
+
message.execution
|
|
451
|
+
)
|
|
452
|
+
});
|
|
453
|
+
} catch {
|
|
454
|
+
fail(new Error("Invalid embedded admin execution message."));
|
|
455
|
+
}
|
|
456
|
+
} else {
|
|
457
|
+
if (!isEmbeddedAdminSessionMessage(event.data) || event.data.requestId !== expectedRequestId)
|
|
458
|
+
return;
|
|
459
|
+
finish({ requestId: event.data.requestId, token: event.data.token });
|
|
355
460
|
}
|
|
356
|
-
finish({ requestId: event.data.requestId, token: event.data.token });
|
|
357
461
|
};
|
|
358
462
|
const acceptChallenge = (event) => {
|
|
359
|
-
if (event.source !== window.parent || event.origin !== consoleOrigin ||
|
|
463
|
+
if (event.source !== window.parent || event.origin !== consoleOrigin || event.ports.length !== 1) {
|
|
464
|
+
for (const port2 of event.ports) port2.close();
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
const challenge = event.data;
|
|
468
|
+
const actionChallenge = challenge?.type === EMBEDDED_ADMIN_CHALLENGE_MESSAGE && challenge.version === EMBEDDED_ADMIN_ACTION_PROTOCOL_VERSION && typeof challenge.requestId === "string" && challenge.requestId.length >= 16 && challenge.requestId.length <= 128;
|
|
469
|
+
const supported = action ? actionChallenge && Array.isArray(challenge?.capabilities) && challenge.capabilities.length === 1 && challenge.capabilities[0] === EMBEDDED_ADMIN_ACTION_CAPABILITY : isEmbeddedAdminChallengeMessage(event.data);
|
|
470
|
+
if (!supported) {
|
|
471
|
+
if (actionChallenge)
|
|
472
|
+
event.ports[0].postMessage({
|
|
473
|
+
type: "01.embedded-admin.error",
|
|
474
|
+
version: 2,
|
|
475
|
+
requestId: challenge.requestId,
|
|
476
|
+
reason: "unsupported"
|
|
477
|
+
});
|
|
360
478
|
for (const port2 of event.ports) port2.close();
|
|
361
479
|
return;
|
|
362
480
|
}
|
|
@@ -369,8 +487,9 @@ function receiveEmbeddedAdminSession(options) {
|
|
|
369
487
|
port.start();
|
|
370
488
|
port.postMessage({
|
|
371
489
|
type: EMBEDDED_ADMIN_READY_MESSAGE,
|
|
372
|
-
version: EMBEDDED_ADMIN_PROTOCOL_VERSION,
|
|
373
|
-
requestId
|
|
490
|
+
version: action ? EMBEDDED_ADMIN_ACTION_PROTOCOL_VERSION : EMBEDDED_ADMIN_PROTOCOL_VERSION,
|
|
491
|
+
requestId,
|
|
492
|
+
...action ? { capabilities: [EMBEDDED_ADMIN_ACTION_CAPABILITY] } : {}
|
|
374
493
|
});
|
|
375
494
|
};
|
|
376
495
|
const timer = setTimeout(() => {
|
|
@@ -385,20 +504,29 @@ function receiveEmbeddedAdminSession(options) {
|
|
|
385
504
|
});
|
|
386
505
|
}
|
|
387
506
|
export {
|
|
507
|
+
EMBEDDED_ADMIN_ACTION_CAPABILITY,
|
|
508
|
+
EMBEDDED_ADMIN_ACTION_PROTOCOL_VERSION,
|
|
388
509
|
EMBEDDED_ADMIN_APP_KEY,
|
|
389
510
|
EMBEDDED_ADMIN_CHALLENGE_MESSAGE,
|
|
511
|
+
EMBEDDED_ADMIN_EXECUTION_AUDIENCE_PREFIX,
|
|
512
|
+
EMBEDDED_ADMIN_MAX_ACTIONS,
|
|
513
|
+
EMBEDDED_ADMIN_MAX_SELECTED_IDS,
|
|
390
514
|
EMBEDDED_ADMIN_PROTOCOL_VERSION,
|
|
391
515
|
EMBEDDED_ADMIN_READY_MESSAGE,
|
|
392
516
|
EMBEDDED_ADMIN_SESSION_MESSAGE,
|
|
393
517
|
EMBEDDED_ADMIN_SESSION_TTL_SECONDS,
|
|
394
518
|
EMBEDDED_ADMIN_TENANT_ROLES,
|
|
519
|
+
embeddedAdminExecutionContextsEqual,
|
|
395
520
|
isEmbeddedAdminChallengeMessage,
|
|
396
521
|
isEmbeddedAdminReadyMessage,
|
|
397
522
|
isEmbeddedAdminSessionMessage,
|
|
523
|
+
normalizeEmbeddedAdminActions,
|
|
398
524
|
normalizeEmbeddedAdminAllowedRoles,
|
|
399
525
|
normalizeEmbeddedAdminBindingConfiguration,
|
|
400
526
|
normalizeEmbeddedAdminExactOrigin,
|
|
527
|
+
normalizeEmbeddedAdminExecutionContext,
|
|
401
528
|
normalizeEmbeddedAdminRelativePath,
|
|
529
|
+
receiveEmbeddedAdminExecution,
|
|
402
530
|
receiveEmbeddedAdminSession
|
|
403
531
|
};
|
|
404
532
|
//# sourceMappingURL=embedded-admin.js.map
|