@01.software/sdk 0.38.0 → 0.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +117 -34
  2. package/dist/analytics/react.cjs.map +1 -1
  3. package/dist/analytics/react.js.map +1 -1
  4. package/dist/analytics.cjs.map +1 -1
  5. package/dist/analytics.js.map +1 -1
  6. package/dist/client.cjs +1219 -5
  7. package/dist/client.cjs.map +1 -1
  8. package/dist/client.d.cts +5 -4
  9. package/dist/client.d.ts +5 -4
  10. package/dist/client.js +1219 -5
  11. package/dist/client.js.map +1 -1
  12. package/dist/{collection-client-BroIWHY1.d.ts → collection-client-CaMgs5KE.d.ts} +14 -8
  13. package/dist/{collection-client-B0J9wMNE.d.cts → collection-client-DVfB0Em1.d.cts} +14 -8
  14. package/dist/errors.cjs +4 -1
  15. package/dist/errors.cjs.map +1 -1
  16. package/dist/errors.js +4 -1
  17. package/dist/errors.js.map +1 -1
  18. package/dist/index.cjs +2787 -2612
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +2 -2
  21. package/dist/index.d.ts +2 -2
  22. package/dist/index.js +2787 -2612
  23. package/dist/index.js.map +1 -1
  24. package/dist/query.cjs +241 -58
  25. package/dist/query.cjs.map +1 -1
  26. package/dist/query.d.cts +148 -23
  27. package/dist/query.d.ts +148 -23
  28. package/dist/query.js +241 -58
  29. package/dist/query.js.map +1 -1
  30. package/dist/realtime.cjs +5 -1
  31. package/dist/realtime.cjs.map +1 -1
  32. package/dist/realtime.js +5 -1
  33. package/dist/realtime.js.map +1 -1
  34. package/dist/server.cjs +1149 -1
  35. package/dist/server.cjs.map +1 -1
  36. package/dist/server.d.cts +4 -4
  37. package/dist/server.d.ts +4 -4
  38. package/dist/server.js +1149 -1
  39. package/dist/server.js.map +1 -1
  40. package/dist/storefront-cache.cjs +144 -0
  41. package/dist/storefront-cache.cjs.map +1 -0
  42. package/dist/storefront-cache.d.cts +24 -0
  43. package/dist/storefront-cache.d.ts +24 -0
  44. package/dist/storefront-cache.js +121 -0
  45. package/dist/storefront-cache.js.map +1 -0
  46. package/dist/{types-CIGscmus.d.cts → types-BQo7UdI9.d.cts} +181 -35
  47. package/dist/{types-D2xYdz4P.d.ts → types-CVf8sCZ-.d.ts} +181 -35
  48. package/dist/ui/canvas/server.cjs +5 -1
  49. package/dist/ui/canvas/server.cjs.map +1 -1
  50. package/dist/ui/canvas/server.js +5 -1
  51. package/dist/ui/canvas/server.js.map +1 -1
  52. package/dist/ui/canvas.cjs +5 -1
  53. package/dist/ui/canvas.cjs.map +1 -1
  54. package/dist/ui/canvas.js +5 -1
  55. package/dist/ui/canvas.js.map +1 -1
  56. package/package.json +13 -3
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/storefront-cache.ts
21
+ var storefront_cache_exports = {};
22
+ __export(storefront_cache_exports, {
23
+ storefrontCacheResources: () => storefrontCacheResources
24
+ });
25
+ module.exports = __toCommonJS(storefront_cache_exports);
26
+
27
+ // src/core/errors.ts
28
+ var SDKError = class extends Error {
29
+ constructor(code, message, status, details, userMessage, suggestion, requestId) {
30
+ super(message);
31
+ this.name = "SDKError";
32
+ this.code = code;
33
+ this.status = status;
34
+ this.details = details;
35
+ this.userMessage = userMessage;
36
+ this.suggestion = suggestion;
37
+ this.requestId = requestId;
38
+ if (Error.captureStackTrace) {
39
+ Error.captureStackTrace(this, new.target);
40
+ }
41
+ }
42
+ getUserMessage() {
43
+ return this.userMessage || this.message;
44
+ }
45
+ toJSON() {
46
+ return {
47
+ name: this.name,
48
+ code: this.code,
49
+ message: this.message,
50
+ status: this.status,
51
+ details: this.details,
52
+ userMessage: this.userMessage,
53
+ suggestion: this.suggestion,
54
+ ...this.requestId !== void 0 && { requestId: this.requestId }
55
+ };
56
+ }
57
+ };
58
+ var ValidationError = class extends SDKError {
59
+ constructor(message, details, userMessage, suggestion, status = 400) {
60
+ super("VALIDATION_ERROR", message, status, details, userMessage, suggestion);
61
+ this.name = "ValidationError";
62
+ }
63
+ };
64
+ var createValidationError = (message, details, userMessage, suggestion, status) => new ValidationError(message, details, userMessage, suggestion, status);
65
+
66
+ // src/utils/storefront-cache.ts
67
+ var CACHE_RESOURCE_VERSION = "storefront:v1";
68
+ function invalidResourceInput(message) {
69
+ return createValidationError(message);
70
+ }
71
+ function encodeResourceSegment(value, label) {
72
+ if (typeof value !== "string" && typeof value !== "number") {
73
+ throw invalidResourceInput(`${label} must be a string or number`);
74
+ }
75
+ if (typeof value === "number" && !Number.isFinite(value)) {
76
+ throw invalidResourceInput(`${label} must be a finite number`);
77
+ }
78
+ const segment = String(value).trim();
79
+ if (!segment) {
80
+ throw invalidResourceInput(`${label} must not be empty`);
81
+ }
82
+ return encodeURIComponent(segment);
83
+ }
84
+ function scopedResource(scope, resource) {
85
+ if (scope == null || typeof scope !== "object") {
86
+ throw invalidResourceInput("cache scope must be an object");
87
+ }
88
+ const candidate = scope;
89
+ const tenantId = encodeResourceSegment(candidate.tenantId, "tenantId");
90
+ const publishableKeyScopeValue = candidate.publishableKeyScope === void 0 ? "default" : candidate.publishableKeyScope;
91
+ const publishableKeyScope = encodeResourceSegment(
92
+ publishableKeyScopeValue,
93
+ "publishableKeyScope"
94
+ );
95
+ return `${CACHE_RESOURCE_VERSION}:tenant:${tenantId}:key:${publishableKeyScope}:resource:${resource}`;
96
+ }
97
+ function listResource(scope, collection) {
98
+ return scopedResource(scope, `${collection}:list`);
99
+ }
100
+ function idDetailResource(scope, collection, id) {
101
+ return scopedResource(
102
+ scope,
103
+ `${collection}:detail:id:${encodeResourceSegment(id, "resource id")}`
104
+ );
105
+ }
106
+ function productDetailResource(scope, identity) {
107
+ const candidate = identity ?? {};
108
+ const hasIdField = candidate.id !== void 0;
109
+ const hasSlugField = candidate.slug !== void 0;
110
+ if (hasIdField === hasSlugField) {
111
+ throw invalidResourceInput(
112
+ "product detail identity must include exactly one non-empty id or slug"
113
+ );
114
+ }
115
+ if (hasIdField) {
116
+ if (typeof candidate.id !== "string" && typeof candidate.id !== "number" || String(candidate.id).trim() === "") {
117
+ throw invalidResourceInput(
118
+ "product detail identity must include exactly one non-empty id or slug"
119
+ );
120
+ }
121
+ return idDetailResource(scope, "products", candidate.id);
122
+ }
123
+ if (typeof candidate.slug !== "string" || candidate.slug.trim() === "") {
124
+ throw invalidResourceInput(
125
+ "product detail identity must include exactly one non-empty id or slug"
126
+ );
127
+ }
128
+ return scopedResource(
129
+ scope,
130
+ `products:detail:slug:${encodeResourceSegment(
131
+ candidate.slug,
132
+ "resource slug"
133
+ )}`
134
+ );
135
+ }
136
+ var storefrontCacheResources = {
137
+ productListing(scope) {
138
+ return listResource(scope, "products");
139
+ },
140
+ productDetail(scope, identity) {
141
+ return productDetailResource(scope, identity);
142
+ }
143
+ };
144
+ //# sourceMappingURL=storefront-cache.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/storefront-cache.ts","../src/core/errors.ts","../src/utils/storefront-cache.ts"],"sourcesContent":["export * from './utils/storefront-cache'\n","export 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\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\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 }\n }\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 }\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 }\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 }\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 }\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 }\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 }\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 }\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 }\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 }\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 }\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 }\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 }\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 }\n}\n\nexport function isSDKError(error: unknown): error is SDKError {\n return error instanceof SDKError\n}\n\nexport function isNetworkError(error: unknown): error is NetworkError {\n return error instanceof NetworkError\n}\n\nexport function isValidationError(error: unknown): error is ValidationError {\n if (error instanceof ValidationError) return true\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\n}\n\nexport function isConfigError(error: unknown): error is ConfigError {\n return error instanceof ConfigError\n}\n\nexport function isTimeoutError(error: unknown): error is TimeoutError {\n return error instanceof TimeoutError\n}\n\nexport function isGoneError(error: unknown): error is GoneError {\n return error instanceof GoneError\n}\n\nexport function isServiceUnavailableError(\n error: unknown,\n): error is ServiceUnavailableError {\n return error instanceof ServiceUnavailableError\n}\n\nexport function isUsageLimitError(error: unknown): error is UsageLimitError {\n return error instanceof UsageLimitError\n}\n\nexport function isAuthError(error: unknown): error is AuthError {\n return error instanceof AuthError\n}\n\nexport function isPermissionError(error: unknown): error is PermissionError {\n return error instanceof PermissionError\n}\n\nexport function isNotFoundError(error: unknown): error is NotFoundError {\n return error instanceof NotFoundError\n}\n\nexport function isConflictError(error: unknown): error is ConflictError {\n return error instanceof ConflictError\n}\n\nexport function isRateLimitError(error: unknown): error is RateLimitError {\n return error instanceof RateLimitError\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 '../errors'\n\nconst CACHE_RESOURCE_VERSION = 'storefront:v1'\n\nexport type StorefrontCacheScope = {\n /**\n * Tenant identifier for the public storefront read.\n */\n tenantId: string | number\n /**\n * Stable, non-secret scope for publishable-key variance. Use a short key id,\n * key fingerprint, or \"default\" when a tenant has one public cache view.\n */\n publishableKeyScope?: string | number\n}\n\nexport type StorefrontCacheProductDetailIdentity =\n | { id: string | number; slug?: never }\n | { id?: never; slug: string }\n\nfunction invalidResourceInput(message: string) {\n return createValidationError(message)\n}\n\nfunction encodeResourceSegment(value: unknown, label: string): string {\n if (typeof value !== 'string' && typeof value !== 'number') {\n throw invalidResourceInput(`${label} must be a string or number`)\n }\n if (typeof value === 'number' && !Number.isFinite(value)) {\n throw invalidResourceInput(`${label} must be a finite number`)\n }\n const segment = String(value).trim()\n if (!segment) {\n throw invalidResourceInput(`${label} must not be empty`)\n }\n return encodeURIComponent(segment)\n}\n\nfunction scopedResource(scope: StorefrontCacheScope, resource: string): string {\n if (scope == null || typeof scope !== 'object') {\n throw invalidResourceInput('cache scope must be an object')\n }\n const candidate = scope as {\n tenantId?: unknown\n publishableKeyScope?: unknown\n }\n const tenantId = encodeResourceSegment(candidate.tenantId, 'tenantId')\n const publishableKeyScopeValue =\n candidate.publishableKeyScope === undefined\n ? 'default'\n : candidate.publishableKeyScope\n const publishableKeyScope = encodeResourceSegment(\n publishableKeyScopeValue,\n 'publishableKeyScope',\n )\n\n return `${CACHE_RESOURCE_VERSION}:tenant:${tenantId}:key:${publishableKeyScope}:resource:${resource}`\n}\n\nfunction listResource(scope: StorefrontCacheScope, collection: string): string {\n return scopedResource(scope, `${collection}:list`)\n}\n\nfunction idDetailResource(\n scope: StorefrontCacheScope,\n collection: string,\n id: string | number,\n): string {\n return scopedResource(\n scope,\n `${collection}:detail:id:${encodeResourceSegment(id, 'resource id')}`,\n )\n}\n\nfunction productDetailResource(\n scope: StorefrontCacheScope,\n identity: StorefrontCacheProductDetailIdentity,\n): string {\n const candidate = (identity ?? {}) as {\n id?: unknown\n slug?: unknown\n }\n const hasIdField = candidate.id !== undefined\n const hasSlugField = candidate.slug !== undefined\n\n if (hasIdField === hasSlugField) {\n throw invalidResourceInput(\n 'product detail identity must include exactly one non-empty id or slug',\n )\n }\n\n if (hasIdField) {\n if (\n (typeof candidate.id !== 'string' && typeof candidate.id !== 'number') ||\n String(candidate.id).trim() === ''\n ) {\n throw invalidResourceInput(\n 'product detail identity must include exactly one non-empty id or slug',\n )\n }\n return idDetailResource(scope, 'products', candidate.id as string | number)\n }\n if (typeof candidate.slug !== 'string' || candidate.slug.trim() === '') {\n throw invalidResourceInput(\n 'product detail identity must include exactly one non-empty id or slug',\n )\n }\n return scopedResource(\n scope,\n `products:detail:slug:${encodeResourceSegment(\n candidate.slug as string,\n 'resource slug',\n )}`,\n )\n}\n\nexport const storefrontCacheResources = {\n productListing(scope: StorefrontCacheScope): string {\n return listResource(scope, 'products')\n },\n productDetail(\n scope: StorefrontCacheScope,\n identity: StorefrontCacheProductDetailIdentity,\n ): string {\n return productDetailResource(scope, identity)\n },\n} as const\n"],"mappings":"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","names":[]}
@@ -0,0 +1,24 @@
1
+ type StorefrontCacheScope = {
2
+ /**
3
+ * Tenant identifier for the public storefront read.
4
+ */
5
+ tenantId: string | number;
6
+ /**
7
+ * Stable, non-secret scope for publishable-key variance. Use a short key id,
8
+ * key fingerprint, or "default" when a tenant has one public cache view.
9
+ */
10
+ publishableKeyScope?: string | number;
11
+ };
12
+ type StorefrontCacheProductDetailIdentity = {
13
+ id: string | number;
14
+ slug?: never;
15
+ } | {
16
+ id?: never;
17
+ slug: string;
18
+ };
19
+ declare const storefrontCacheResources: {
20
+ readonly productListing: (scope: StorefrontCacheScope) => string;
21
+ readonly productDetail: (scope: StorefrontCacheScope, identity: StorefrontCacheProductDetailIdentity) => string;
22
+ };
23
+
24
+ export { type StorefrontCacheProductDetailIdentity, type StorefrontCacheScope, storefrontCacheResources };
@@ -0,0 +1,24 @@
1
+ type StorefrontCacheScope = {
2
+ /**
3
+ * Tenant identifier for the public storefront read.
4
+ */
5
+ tenantId: string | number;
6
+ /**
7
+ * Stable, non-secret scope for publishable-key variance. Use a short key id,
8
+ * key fingerprint, or "default" when a tenant has one public cache view.
9
+ */
10
+ publishableKeyScope?: string | number;
11
+ };
12
+ type StorefrontCacheProductDetailIdentity = {
13
+ id: string | number;
14
+ slug?: never;
15
+ } | {
16
+ id?: never;
17
+ slug: string;
18
+ };
19
+ declare const storefrontCacheResources: {
20
+ readonly productListing: (scope: StorefrontCacheScope) => string;
21
+ readonly productDetail: (scope: StorefrontCacheScope, identity: StorefrontCacheProductDetailIdentity) => string;
22
+ };
23
+
24
+ export { type StorefrontCacheProductDetailIdentity, type StorefrontCacheScope, storefrontCacheResources };
@@ -0,0 +1,121 @@
1
+ // src/core/errors.ts
2
+ var SDKError = class extends Error {
3
+ constructor(code, message, status, details, userMessage, suggestion, requestId) {
4
+ super(message);
5
+ this.name = "SDKError";
6
+ this.code = code;
7
+ this.status = status;
8
+ this.details = details;
9
+ this.userMessage = userMessage;
10
+ this.suggestion = suggestion;
11
+ this.requestId = requestId;
12
+ if (Error.captureStackTrace) {
13
+ Error.captureStackTrace(this, new.target);
14
+ }
15
+ }
16
+ getUserMessage() {
17
+ return this.userMessage || this.message;
18
+ }
19
+ toJSON() {
20
+ return {
21
+ name: this.name,
22
+ code: this.code,
23
+ message: this.message,
24
+ status: this.status,
25
+ details: this.details,
26
+ userMessage: this.userMessage,
27
+ suggestion: this.suggestion,
28
+ ...this.requestId !== void 0 && { requestId: this.requestId }
29
+ };
30
+ }
31
+ };
32
+ var ValidationError = class extends SDKError {
33
+ constructor(message, details, userMessage, suggestion, status = 400) {
34
+ super("VALIDATION_ERROR", message, status, details, userMessage, suggestion);
35
+ this.name = "ValidationError";
36
+ }
37
+ };
38
+ var createValidationError = (message, details, userMessage, suggestion, status) => new ValidationError(message, details, userMessage, suggestion, status);
39
+
40
+ // src/utils/storefront-cache.ts
41
+ var CACHE_RESOURCE_VERSION = "storefront:v1";
42
+ function invalidResourceInput(message) {
43
+ return createValidationError(message);
44
+ }
45
+ function encodeResourceSegment(value, label) {
46
+ if (typeof value !== "string" && typeof value !== "number") {
47
+ throw invalidResourceInput(`${label} must be a string or number`);
48
+ }
49
+ if (typeof value === "number" && !Number.isFinite(value)) {
50
+ throw invalidResourceInput(`${label} must be a finite number`);
51
+ }
52
+ const segment = String(value).trim();
53
+ if (!segment) {
54
+ throw invalidResourceInput(`${label} must not be empty`);
55
+ }
56
+ return encodeURIComponent(segment);
57
+ }
58
+ function scopedResource(scope, resource) {
59
+ if (scope == null || typeof scope !== "object") {
60
+ throw invalidResourceInput("cache scope must be an object");
61
+ }
62
+ const candidate = scope;
63
+ const tenantId = encodeResourceSegment(candidate.tenantId, "tenantId");
64
+ const publishableKeyScopeValue = candidate.publishableKeyScope === void 0 ? "default" : candidate.publishableKeyScope;
65
+ const publishableKeyScope = encodeResourceSegment(
66
+ publishableKeyScopeValue,
67
+ "publishableKeyScope"
68
+ );
69
+ return `${CACHE_RESOURCE_VERSION}:tenant:${tenantId}:key:${publishableKeyScope}:resource:${resource}`;
70
+ }
71
+ function listResource(scope, collection) {
72
+ return scopedResource(scope, `${collection}:list`);
73
+ }
74
+ function idDetailResource(scope, collection, id) {
75
+ return scopedResource(
76
+ scope,
77
+ `${collection}:detail:id:${encodeResourceSegment(id, "resource id")}`
78
+ );
79
+ }
80
+ function productDetailResource(scope, identity) {
81
+ const candidate = identity ?? {};
82
+ const hasIdField = candidate.id !== void 0;
83
+ const hasSlugField = candidate.slug !== void 0;
84
+ if (hasIdField === hasSlugField) {
85
+ throw invalidResourceInput(
86
+ "product detail identity must include exactly one non-empty id or slug"
87
+ );
88
+ }
89
+ if (hasIdField) {
90
+ if (typeof candidate.id !== "string" && typeof candidate.id !== "number" || String(candidate.id).trim() === "") {
91
+ throw invalidResourceInput(
92
+ "product detail identity must include exactly one non-empty id or slug"
93
+ );
94
+ }
95
+ return idDetailResource(scope, "products", candidate.id);
96
+ }
97
+ if (typeof candidate.slug !== "string" || candidate.slug.trim() === "") {
98
+ throw invalidResourceInput(
99
+ "product detail identity must include exactly one non-empty id or slug"
100
+ );
101
+ }
102
+ return scopedResource(
103
+ scope,
104
+ `products:detail:slug:${encodeResourceSegment(
105
+ candidate.slug,
106
+ "resource slug"
107
+ )}`
108
+ );
109
+ }
110
+ var storefrontCacheResources = {
111
+ productListing(scope) {
112
+ return listResource(scope, "products");
113
+ },
114
+ productDetail(scope, identity) {
115
+ return productDetailResource(scope, identity);
116
+ }
117
+ };
118
+ export {
119
+ storefrontCacheResources
120
+ };
121
+ //# sourceMappingURL=storefront-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/errors.ts","../src/utils/storefront-cache.ts"],"sourcesContent":["export 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\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\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 }\n }\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 }\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 }\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 }\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 }\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 }\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 }\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 }\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 }\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 }\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 }\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 }\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 }\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 }\n}\n\nexport function isSDKError(error: unknown): error is SDKError {\n return error instanceof SDKError\n}\n\nexport function isNetworkError(error: unknown): error is NetworkError {\n return error instanceof NetworkError\n}\n\nexport function isValidationError(error: unknown): error is ValidationError {\n if (error instanceof ValidationError) return true\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\n}\n\nexport function isConfigError(error: unknown): error is ConfigError {\n return error instanceof ConfigError\n}\n\nexport function isTimeoutError(error: unknown): error is TimeoutError {\n return error instanceof TimeoutError\n}\n\nexport function isGoneError(error: unknown): error is GoneError {\n return error instanceof GoneError\n}\n\nexport function isServiceUnavailableError(\n error: unknown,\n): error is ServiceUnavailableError {\n return error instanceof ServiceUnavailableError\n}\n\nexport function isUsageLimitError(error: unknown): error is UsageLimitError {\n return error instanceof UsageLimitError\n}\n\nexport function isAuthError(error: unknown): error is AuthError {\n return error instanceof AuthError\n}\n\nexport function isPermissionError(error: unknown): error is PermissionError {\n return error instanceof PermissionError\n}\n\nexport function isNotFoundError(error: unknown): error is NotFoundError {\n return error instanceof NotFoundError\n}\n\nexport function isConflictError(error: unknown): error is ConflictError {\n return error instanceof ConflictError\n}\n\nexport function isRateLimitError(error: unknown): error is RateLimitError {\n return error instanceof RateLimitError\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 '../errors'\n\nconst CACHE_RESOURCE_VERSION = 'storefront:v1'\n\nexport type StorefrontCacheScope = {\n /**\n * Tenant identifier for the public storefront read.\n */\n tenantId: string | number\n /**\n * Stable, non-secret scope for publishable-key variance. Use a short key id,\n * key fingerprint, or \"default\" when a tenant has one public cache view.\n */\n publishableKeyScope?: string | number\n}\n\nexport type StorefrontCacheProductDetailIdentity =\n | { id: string | number; slug?: never }\n | { id?: never; slug: string }\n\nfunction invalidResourceInput(message: string) {\n return createValidationError(message)\n}\n\nfunction encodeResourceSegment(value: unknown, label: string): string {\n if (typeof value !== 'string' && typeof value !== 'number') {\n throw invalidResourceInput(`${label} must be a string or number`)\n }\n if (typeof value === 'number' && !Number.isFinite(value)) {\n throw invalidResourceInput(`${label} must be a finite number`)\n }\n const segment = String(value).trim()\n if (!segment) {\n throw invalidResourceInput(`${label} must not be empty`)\n }\n return encodeURIComponent(segment)\n}\n\nfunction scopedResource(scope: StorefrontCacheScope, resource: string): string {\n if (scope == null || typeof scope !== 'object') {\n throw invalidResourceInput('cache scope must be an object')\n }\n const candidate = scope as {\n tenantId?: unknown\n publishableKeyScope?: unknown\n }\n const tenantId = encodeResourceSegment(candidate.tenantId, 'tenantId')\n const publishableKeyScopeValue =\n candidate.publishableKeyScope === undefined\n ? 'default'\n : candidate.publishableKeyScope\n const publishableKeyScope = encodeResourceSegment(\n publishableKeyScopeValue,\n 'publishableKeyScope',\n )\n\n return `${CACHE_RESOURCE_VERSION}:tenant:${tenantId}:key:${publishableKeyScope}:resource:${resource}`\n}\n\nfunction listResource(scope: StorefrontCacheScope, collection: string): string {\n return scopedResource(scope, `${collection}:list`)\n}\n\nfunction idDetailResource(\n scope: StorefrontCacheScope,\n collection: string,\n id: string | number,\n): string {\n return scopedResource(\n scope,\n `${collection}:detail:id:${encodeResourceSegment(id, 'resource id')}`,\n )\n}\n\nfunction productDetailResource(\n scope: StorefrontCacheScope,\n identity: StorefrontCacheProductDetailIdentity,\n): string {\n const candidate = (identity ?? {}) as {\n id?: unknown\n slug?: unknown\n }\n const hasIdField = candidate.id !== undefined\n const hasSlugField = candidate.slug !== undefined\n\n if (hasIdField === hasSlugField) {\n throw invalidResourceInput(\n 'product detail identity must include exactly one non-empty id or slug',\n )\n }\n\n if (hasIdField) {\n if (\n (typeof candidate.id !== 'string' && typeof candidate.id !== 'number') ||\n String(candidate.id).trim() === ''\n ) {\n throw invalidResourceInput(\n 'product detail identity must include exactly one non-empty id or slug',\n )\n }\n return idDetailResource(scope, 'products', candidate.id as string | number)\n }\n if (typeof candidate.slug !== 'string' || candidate.slug.trim() === '') {\n throw invalidResourceInput(\n 'product detail identity must include exactly one non-empty id or slug',\n )\n }\n return scopedResource(\n scope,\n `products:detail:slug:${encodeResourceSegment(\n candidate.slug as string,\n 'resource slug',\n )}`,\n )\n}\n\nexport const storefrontCacheResources = {\n productListing(scope: StorefrontCacheScope): string {\n return listResource(scope, 'products')\n },\n productDetail(\n scope: StorefrontCacheScope,\n identity: StorefrontCacheProductDetailIdentity,\n ): string {\n return productDetailResource(scope, identity)\n },\n} as const\n"],"mappings":"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","names":[]}