threeu-sdk 0.1.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.
- package/README.md +176 -0
- package/dist/admin/index.d.ts +22 -0
- package/dist/admin/index.js +17 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/chunk-2TGBSV6L.js +197 -0
- package/dist/chunk-2TGBSV6L.js.map +1 -0
- package/dist/chunk-6S7OFN23.js +81 -0
- package/dist/chunk-6S7OFN23.js.map +1 -0
- package/dist/chunk-6ZCBDWWQ.js +140 -0
- package/dist/chunk-6ZCBDWWQ.js.map +1 -0
- package/dist/chunk-BCUODRZW.js +78 -0
- package/dist/chunk-BCUODRZW.js.map +1 -0
- package/dist/chunk-H3XILKGI.js +70 -0
- package/dist/chunk-H3XILKGI.js.map +1 -0
- package/dist/chunk-HYSJ6YPN.js +425 -0
- package/dist/chunk-HYSJ6YPN.js.map +1 -0
- package/dist/chunk-LFF5LPWT.js +122 -0
- package/dist/chunk-LFF5LPWT.js.map +1 -0
- package/dist/chunk-OXAQGEMQ.js +3 -0
- package/dist/chunk-OXAQGEMQ.js.map +1 -0
- package/dist/chunk-USFJIM5K.js +195 -0
- package/dist/chunk-USFJIM5K.js.map +1 -0
- package/dist/chunk-ZWLFJIAM.js +69 -0
- package/dist/chunk-ZWLFJIAM.js.map +1 -0
- package/dist/define-B6ZJMWDI.d.ts +24 -0
- package/dist/developer/index.d.ts +120 -0
- package/dist/developer/index.js +106 -0
- package/dist/developer/index.js.map +1 -0
- package/dist/errors/index.d.ts +83 -0
- package/dist/errors/index.js +4 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index-ksmDFDZc.d.ts +90 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin/index.d.ts +13 -0
- package/dist/plugin/index.js +27 -0
- package/dist/plugin/index.js.map +1 -0
- package/dist/plugin/server/index.d.ts +70 -0
- package/dist/plugin/server/index.js +105 -0
- package/dist/plugin/server/index.js.map +1 -0
- package/dist/pos/index.d.ts +26 -0
- package/dist/pos/index.js +24 -0
- package/dist/pos/index.js.map +1 -0
- package/dist/react/index.d.ts +5 -0
- package/dist/react/index.js +7 -0
- package/dist/react/index.js.map +1 -0
- package/dist/session-BFDRm-KJ.d.ts +94 -0
- package/dist/storefront/index.d.ts +76 -0
- package/dist/storefront/index.js +6 -0
- package/dist/storefront/index.js.map +1 -0
- package/dist/testing/index.d.ts +82 -0
- package/dist/testing/index.js +106 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/theme/index.d.ts +109 -0
- package/dist/theme/index.js +152 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/threeu-BesFjXdw.d.ts +143 -0
- package/dist/types-BoGD3IXz.d.ts +173 -0
- package/dist/types-DfyYnoLn.d.ts +248 -0
- package/dist/webhooks/index.d.ts +36 -0
- package/dist/webhooks/index.js +4 -0
- package/dist/webhooks/index.js.map +1 -0
- package/package.json +110 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed error hierarchy. Backend responses (both the `{success,message}`
|
|
3
|
+
* convention and Laravel's `{message,errors}` validation shape — see
|
|
4
|
+
* docs/ARCHITECTURE_MAP.md §10) are normalized into these classes so callers can
|
|
5
|
+
* `catch` precisely and branch on `err.retryable`.
|
|
6
|
+
*/
|
|
7
|
+
interface ThreeuErrorInit {
|
|
8
|
+
code?: string;
|
|
9
|
+
status?: number;
|
|
10
|
+
requestId?: string;
|
|
11
|
+
details?: unknown;
|
|
12
|
+
cause?: unknown;
|
|
13
|
+
retryable?: boolean;
|
|
14
|
+
}
|
|
15
|
+
declare class ThreeuError extends Error {
|
|
16
|
+
readonly code: string;
|
|
17
|
+
readonly status?: number;
|
|
18
|
+
readonly requestId?: string;
|
|
19
|
+
readonly details?: unknown;
|
|
20
|
+
readonly cause?: unknown;
|
|
21
|
+
readonly retryable: boolean;
|
|
22
|
+
constructor(message: string, init?: ThreeuErrorInit);
|
|
23
|
+
toJSON(): Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
/** A non-2xx HTTP response that didn't match a more specific subclass. */
|
|
26
|
+
declare class ThreeuApiError extends ThreeuError {
|
|
27
|
+
}
|
|
28
|
+
declare class ThreeuAuthError extends ThreeuError {
|
|
29
|
+
constructor(message?: string, init?: ThreeuErrorInit);
|
|
30
|
+
}
|
|
31
|
+
declare class ThreeuPermissionError extends ThreeuError {
|
|
32
|
+
constructor(message?: string, init?: ThreeuErrorInit);
|
|
33
|
+
}
|
|
34
|
+
declare class ThreeuValidationError extends ThreeuError {
|
|
35
|
+
/** Field → messages map, mirroring Laravel's `errors` bag. */
|
|
36
|
+
readonly fields: Record<string, string[]>;
|
|
37
|
+
constructor(message?: string, init?: ThreeuErrorInit & {
|
|
38
|
+
fields?: Record<string, string[]>;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
declare class ThreeuNotFoundError extends ThreeuError {
|
|
42
|
+
constructor(message?: string, init?: ThreeuErrorInit);
|
|
43
|
+
}
|
|
44
|
+
declare class ThreeuConflictError extends ThreeuError {
|
|
45
|
+
constructor(message?: string, init?: ThreeuErrorInit);
|
|
46
|
+
}
|
|
47
|
+
declare class ThreeuRateLimitError extends ThreeuError {
|
|
48
|
+
/** Seconds to wait before retrying, from the `Retry-After` header if present. */
|
|
49
|
+
readonly retryAfterSeconds?: number;
|
|
50
|
+
constructor(message?: string, init?: ThreeuErrorInit & {
|
|
51
|
+
retryAfterSeconds?: number;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
declare class ThreeuTimeoutError extends ThreeuError {
|
|
55
|
+
constructor(message?: string, init?: ThreeuErrorInit);
|
|
56
|
+
}
|
|
57
|
+
declare class ThreeuNetworkError extends ThreeuError {
|
|
58
|
+
constructor(message?: string, init?: ThreeuErrorInit);
|
|
59
|
+
}
|
|
60
|
+
declare class ThreeuWebhookSignatureError extends ThreeuError {
|
|
61
|
+
constructor(message?: string, init?: ThreeuErrorInit);
|
|
62
|
+
}
|
|
63
|
+
declare class ThreeuManifestError extends ThreeuError {
|
|
64
|
+
readonly issues: string[];
|
|
65
|
+
constructor(message?: string, init?: ThreeuErrorInit & {
|
|
66
|
+
issues?: string[];
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
declare class ThreeuProviderError extends ThreeuError {
|
|
70
|
+
constructor(message?: string, init?: ThreeuErrorInit);
|
|
71
|
+
}
|
|
72
|
+
/** Thrown by experimental/stubbed methods whose backend route is not yet live. */
|
|
73
|
+
declare class ThreeuNotImplementedError extends ThreeuError {
|
|
74
|
+
constructor(message?: string, init?: ThreeuErrorInit);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Map an HTTP response (status + parsed body) into the right error class.
|
|
78
|
+
* Handles both ThreeU's `{success,message}` envelope and Laravel's
|
|
79
|
+
* `{message, errors}` validation shape.
|
|
80
|
+
*/
|
|
81
|
+
declare function errorFromResponse(status: number, body: unknown, requestId?: string, retryAfterSeconds?: number): ThreeuError;
|
|
82
|
+
|
|
83
|
+
export { ThreeuApiError, ThreeuAuthError, ThreeuConflictError, ThreeuError, type ThreeuErrorInit, ThreeuManifestError, ThreeuNetworkError, ThreeuNotFoundError, ThreeuNotImplementedError, ThreeuPermissionError, ThreeuProviderError, ThreeuRateLimitError, ThreeuTimeoutError, ThreeuValidationError, ThreeuWebhookSignatureError, errorFromResponse };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import '../chunk-OXAQGEMQ.js';
|
|
2
|
+
export { ThreeuApiError, ThreeuAuthError, ThreeuConflictError, ThreeuError, ThreeuManifestError, ThreeuNetworkError, ThreeuNotFoundError, ThreeuNotImplementedError, ThreeuPermissionError, ThreeuProviderError, ThreeuRateLimitError, ThreeuTimeoutError, ThreeuValidationError, ThreeuWebhookSignatureError, errorFromResponse } from '../chunk-LFF5LPWT.js';
|
|
3
|
+
//# sourceMappingURL=index.js.map
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { ThreeuStorefront } from './storefront/index.js';
|
|
3
|
+
import { I as Id, C as Collection, d as Product } from './types-DfyYnoLn.js';
|
|
4
|
+
import { v as ThemeEditableField } from './types-BoGD3IXz.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Theme runtime: the editable-field registry + active customization store.
|
|
8
|
+
*
|
|
9
|
+
* `T*` components and `TColor()` register the fields they expose (so a build step
|
|
10
|
+
* / the theme editor can enumerate every customizable field) and resolve their
|
|
11
|
+
* current value from the active customization map that `ThemeProvider` installs.
|
|
12
|
+
*
|
|
13
|
+
* The active store is module-level so the non-hook `TColor(name, default)`
|
|
14
|
+
* helper can resolve values during render. This is intentionally simple and is
|
|
15
|
+
* not concurrent-render safe; SSR/streaming themes should read values via the
|
|
16
|
+
* `useThemeField` hook instead.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
type FieldKind = ThemeEditableField["kind"];
|
|
20
|
+
/** Register (or update) an editable field. Idempotent by `name`. */
|
|
21
|
+
declare function registerField(name: string, kind: FieldKind, defaultValue?: unknown, label?: string): void;
|
|
22
|
+
/** Resolve a field's current value: customization override → registered default. */
|
|
23
|
+
declare function resolveValue<T = unknown>(name: string, fallback?: T): T;
|
|
24
|
+
/** Install the active customization map (called by ThemeProvider during render). */
|
|
25
|
+
declare function setActiveCustomization(values: Record<string, unknown> | undefined): void;
|
|
26
|
+
/** Snapshot every registered field — used for manifest generation / extraction. */
|
|
27
|
+
declare function extractFields(): ThemeEditableField[];
|
|
28
|
+
/** Clear the registry (tests / hot reload). */
|
|
29
|
+
declare function resetRegistry(): void;
|
|
30
|
+
|
|
31
|
+
interface ThemeBrandInfo {
|
|
32
|
+
id: Id;
|
|
33
|
+
name?: string;
|
|
34
|
+
[key: string]: unknown;
|
|
35
|
+
}
|
|
36
|
+
interface ThemeContextValue {
|
|
37
|
+
customization: Record<string, unknown>;
|
|
38
|
+
brand?: ThemeBrandInfo;
|
|
39
|
+
locale: string;
|
|
40
|
+
currency: string;
|
|
41
|
+
preview: boolean;
|
|
42
|
+
storefront?: ThreeuStorefront;
|
|
43
|
+
}
|
|
44
|
+
interface ThemeProviderProps {
|
|
45
|
+
children: ReactNode;
|
|
46
|
+
customization?: Record<string, unknown>;
|
|
47
|
+
brand?: ThemeBrandInfo;
|
|
48
|
+
locale?: string;
|
|
49
|
+
currency?: string;
|
|
50
|
+
preview?: boolean;
|
|
51
|
+
storefront?: ThreeuStorefront;
|
|
52
|
+
}
|
|
53
|
+
declare function ThemeProvider(props: ThemeProviderProps): JSX.Element;
|
|
54
|
+
interface ThreeuThemeProviderProps extends Omit<ThemeProviderProps, "storefront"> {
|
|
55
|
+
publicToken?: string;
|
|
56
|
+
baseUrl?: string;
|
|
57
|
+
}
|
|
58
|
+
/** Convenience provider that builds a storefront client from a public token. */
|
|
59
|
+
declare function ThreeuThemeProvider(props: ThreeuThemeProviderProps): JSX.Element;
|
|
60
|
+
declare function useThemeContext(): ThemeContextValue;
|
|
61
|
+
declare function useTheme(): ThemeContextValue;
|
|
62
|
+
declare function useBrand(): ThemeBrandInfo | undefined;
|
|
63
|
+
declare function useLocale(): string;
|
|
64
|
+
declare function useCurrency(): string;
|
|
65
|
+
/** SSR/concurrent-safe field read: registers the field and returns its value. */
|
|
66
|
+
declare function useThemeField<T = unknown>(name: string, kind: FieldKind, defaultValue?: T): T;
|
|
67
|
+
interface AsyncState<T> {
|
|
68
|
+
data: T | undefined;
|
|
69
|
+
loading: boolean;
|
|
70
|
+
error: Error | undefined;
|
|
71
|
+
}
|
|
72
|
+
declare function useProducts(params?: {
|
|
73
|
+
collection?: string;
|
|
74
|
+
limit?: number;
|
|
75
|
+
}): AsyncState<Product[]>;
|
|
76
|
+
declare function useCollections(params?: {
|
|
77
|
+
limit?: number;
|
|
78
|
+
}): AsyncState<Collection[]>;
|
|
79
|
+
declare function useCart(): {
|
|
80
|
+
cart: Record<string, unknown> | undefined;
|
|
81
|
+
create: () => Promise<Record<string, unknown>>;
|
|
82
|
+
};
|
|
83
|
+
declare function useCustomer(): {
|
|
84
|
+
customer: Record<string, unknown> | undefined;
|
|
85
|
+
};
|
|
86
|
+
declare function useCheckout(): {
|
|
87
|
+
checkout: (input: Record<string, unknown>) => Promise<void>;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export { type AsyncState as A, type FieldKind as F, type ThemeBrandInfo as T, type ThemeContextValue as a, ThemeProvider as b, type ThemeProviderProps as c, ThreeuThemeProvider as d, type ThreeuThemeProviderProps as e, extractFields as f, resetRegistry as g, resolveValue as h, useCart as i, useCheckout as j, useCollections as k, useCurrency as l, useCustomer as m, useLocale as n, useProducts as o, useTheme as p, useThemeContext as q, registerField as r, setActiveCustomization as s, useThemeField as t, useBrand as u };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export { B as BrandClient, T as Threeu, a as ThreeuOptions } from './threeu-BesFjXdw.js';
|
|
2
|
+
import { h as ThreeuTelemetryOptions, k as ThreeuLogEvent, g as ThreeuLogger } from './types-DfyYnoLn.js';
|
|
3
|
+
export { B as BaseRecord, C as Collection, a as Customer, D as Discount, H as HttpMethod, I as Id, b as InventoryItem, L as ListParams, c as Location, M as Money, O as Order, f as Page, l as PageMeta, P as Payment, d as Product, e as ProductInput, R as RequestOptions, m as SECRET_TOKEN_TYPES, S as ShippingRate, n as ThreeuAppInfo, i as ThreeuClientOptions, o as ThreeuEventType, T as ThreeuHttpClient, p as ThreeuRuntime, j as TokenType, q as detectRuntime, r as isBrowserLike, s as isDevelopment, t as iteratePages, u as normalizePage } from './types-DfyYnoLn.js';
|
|
4
|
+
export { ThreeuApiError, ThreeuAuthError, ThreeuConflictError, ThreeuError, ThreeuManifestError, ThreeuNetworkError, ThreeuNotFoundError, ThreeuNotImplementedError, ThreeuPermissionError, ThreeuProviderError, ThreeuRateLimitError, ThreeuTimeoutError, ThreeuValidationError, ThreeuWebhookSignatureError } from './errors/index.js';
|
|
5
|
+
import './session-BFDRm-KJ.js';
|
|
6
|
+
|
|
7
|
+
/** Redact sensitive header values, returning a safe-to-log copy. */
|
|
8
|
+
declare function redactHeaders(headers: Record<string, string> | Headers): Record<string, string>;
|
|
9
|
+
/**
|
|
10
|
+
* Deep-redact an arbitrary value for logging. Replaces sensitive keys with
|
|
11
|
+
* `[redacted]` and caps depth so we never serialize huge nested payloads.
|
|
12
|
+
*/
|
|
13
|
+
declare function redactValue(input: unknown, includePii?: boolean, depth?: number): unknown;
|
|
14
|
+
/**
|
|
15
|
+
* Collapse a concrete path into a template by eliding ids, so telemetry groups
|
|
16
|
+
* `/plugins/42/webhook` and `/plugins/99/webhook` together as
|
|
17
|
+
* `/plugins/:id/webhook`. Numeric and uuid-like segments are masked.
|
|
18
|
+
*/
|
|
19
|
+
declare function templatizePath(path: string): string;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Single source of truth for the SDK version. Emitted in telemetry events and
|
|
23
|
+
* the User-Agent / X-Threeu-Sdk-Version header. Keep in sync with package.json.
|
|
24
|
+
*/
|
|
25
|
+
declare const SDK_VERSION = "0.1.0";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Dev-time safety warnings. The SDK proactively warns about dangerous usage
|
|
29
|
+
* (brief §"detect obviously unsafe usage"): secret tokens in a browser,
|
|
30
|
+
* insecure base URLs in production, etc. Warnings are deduped and silent in
|
|
31
|
+
* production unless a logger is wired.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/** Emit a console warning at most once per unique message. */
|
|
35
|
+
declare function warnOnce(key: string, message: string): void;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Telemetry collector. Buffers safe-to-send SDK events, samples them, and flushes
|
|
39
|
+
* batches to a configurable endpoint. Best-effort: a failed flush is swallowed so
|
|
40
|
+
* telemetry can never break the host application. Payloads are redacted before
|
|
41
|
+
* they leave the process.
|
|
42
|
+
*
|
|
43
|
+
* The backend telemetry route (POST /api/sdk/events) is NOT live yet
|
|
44
|
+
* (docs/ARCHITECTURE_MAP.md §13) — until it ships, point `endpoint` at your own
|
|
45
|
+
* collector or leave telemetry disabled.
|
|
46
|
+
*/
|
|
47
|
+
declare class TelemetryClient {
|
|
48
|
+
private readonly enabled;
|
|
49
|
+
private readonly endpoint?;
|
|
50
|
+
private readonly sampleRate;
|
|
51
|
+
private readonly flushIntervalMs;
|
|
52
|
+
private readonly maxBatchSize;
|
|
53
|
+
private readonly fetchImpl?;
|
|
54
|
+
private buffer;
|
|
55
|
+
private timer;
|
|
56
|
+
constructor(options?: ThreeuTelemetryOptions, fetchImpl?: typeof fetch);
|
|
57
|
+
/** Record an event. Sampling + buffering applied here; never throws. */
|
|
58
|
+
record(event: ThreeuLogEvent): void;
|
|
59
|
+
/** Flush buffered events immediately. Resolves even if the network call fails. */
|
|
60
|
+
flush(): Promise<void>;
|
|
61
|
+
/** Stop the background flush timer and flush any remaining events. */
|
|
62
|
+
close(): Promise<void>;
|
|
63
|
+
private ensureTimer;
|
|
64
|
+
}
|
|
65
|
+
/** Fan an event out to both the user logger and the telemetry collector. */
|
|
66
|
+
declare function emitEvent(event: ThreeuLogEvent, logger: ThreeuLogger | undefined, telemetry: TelemetryClient | undefined): void;
|
|
67
|
+
|
|
68
|
+
export { SDK_VERSION, TelemetryClient, ThreeuLogEvent, ThreeuLogger, ThreeuTelemetryOptions, emitEvent, redactHeaders, redactValue, templatizePath, warnOnce };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import './chunk-OXAQGEMQ.js';
|
|
2
|
+
export { BrandClient, Threeu } from './chunk-2TGBSV6L.js';
|
|
3
|
+
import './chunk-BCUODRZW.js';
|
|
4
|
+
export { Page, SDK_VERSION, TelemetryClient, ThreeuHttpClient, emitEvent, iteratePages, normalizePage, redactHeaders, redactValue, templatizePath } from './chunk-HYSJ6YPN.js';
|
|
5
|
+
export { SECRET_TOKEN_TYPES, detectRuntime, isBrowserLike, isDevelopment, warnOnce } from './chunk-H3XILKGI.js';
|
|
6
|
+
export { ThreeuApiError, ThreeuAuthError, ThreeuConflictError, ThreeuError, ThreeuManifestError, ThreeuNetworkError, ThreeuNotFoundError, ThreeuNotImplementedError, ThreeuPermissionError, ThreeuProviderError, ThreeuRateLimitError, ThreeuTimeoutError, ThreeuValidationError, ThreeuWebhookSignatureError } from './chunk-LFF5LPWT.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { D as DefinedApp, a as DefinedPlugin, c as createPlugin, d as defineApp, b as definePlugin } from '../define-B6ZJMWDI.js';
|
|
2
|
+
import { A as AppDefinition, a as AdminAppManifest, b as POSAppManifest, c as PluginDefinition, P as PluginManifest, T as ThemeDefinition, d as ThemeManifest } from '../types-BoGD3IXz.js';
|
|
3
|
+
export { e as ActionDefinition, f as ActionManifest, g as AdminBlock, C as ConfigFieldDefinition, h as ConfigFieldType, i as ConfigSchema, E as ExtensionPoint, H as HttpVerb, O as Ownership, j as Permission, k as PluginActionManifest, l as PluginCategory, m as PluginWebhookManifest, n as ProviderAuthManifest, o as ProviderDefinition, p as ProviderManifest, q as ProviderType, R as RemoteHttpProviderDefinition, r as RemoteHttpProviderManifest, S as SimpleProviderDefinition, s as SurfaceType, t as TriggerMode, W as WebhookDefinition } from '../types-BoGD3IXz.js';
|
|
4
|
+
export { ThreeuManifestError } from '../errors/index.js';
|
|
5
|
+
|
|
6
|
+
/** Validate + normalize a plugin definition into its manifest JSON. */
|
|
7
|
+
declare function buildPluginManifest(def: PluginDefinition): PluginManifest;
|
|
8
|
+
/** Validate + normalize an admin/POS app definition into its manifest JSON. */
|
|
9
|
+
declare function buildAppManifest(def: AppDefinition): AdminAppManifest | POSAppManifest;
|
|
10
|
+
/** Validate + normalize a theme definition into its manifest JSON. */
|
|
11
|
+
declare function buildThemeManifest(def: ThemeDefinition): ThemeManifest;
|
|
12
|
+
|
|
13
|
+
export { AdminAppManifest, AppDefinition, POSAppManifest, PluginDefinition, PluginManifest, buildAppManifest, buildPluginManifest, buildThemeManifest };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { buildPluginManifest, buildAppManifest } from '../chunk-USFJIM5K.js';
|
|
2
|
+
export { buildAppManifest, buildPluginManifest, buildThemeManifest } from '../chunk-USFJIM5K.js';
|
|
3
|
+
import '../chunk-H3XILKGI.js';
|
|
4
|
+
export { ThreeuManifestError } from '../chunk-LFF5LPWT.js';
|
|
5
|
+
|
|
6
|
+
// src/plugin/define.ts
|
|
7
|
+
function definePlugin(definition) {
|
|
8
|
+
const manifest = buildPluginManifest(definition);
|
|
9
|
+
return {
|
|
10
|
+
definition,
|
|
11
|
+
manifest,
|
|
12
|
+
toJSON: () => manifest
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
var createPlugin = definePlugin;
|
|
16
|
+
function defineApp(definition) {
|
|
17
|
+
const manifest = buildAppManifest(definition);
|
|
18
|
+
return {
|
|
19
|
+
definition,
|
|
20
|
+
manifest,
|
|
21
|
+
toJSON: () => manifest
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export { createPlugin, defineApp, definePlugin };
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/plugin/define.ts"],"names":[],"mappings":";;;;;;AAwBO,SAAS,aAAa,UAAA,EAA6C;AACxE,EAAA,MAAM,QAAA,GAAW,oBAAoB,UAAU,CAAA;AAC/C,EAAA,OAAO;AAAA,IACL,UAAA;AAAA,IACA,QAAA;AAAA,IACA,QAAQ,MAAM;AAAA,GAChB;AACF;AAGO,IAAM,YAAA,GAAe;AASrB,SAAS,UAAU,UAAA,EAAuC;AAC/D,EAAA,MAAM,QAAA,GAAW,iBAAiB,UAAU,CAAA;AAC5C,EAAA,OAAO;AAAA,IACL,UAAA;AAAA,IACA,QAAA;AAAA,IACA,QAAQ,MAAM;AAAA,GAChB;AACF","file":"index.js","sourcesContent":["/**\n * definePlugin / createPlugin / defineApp — developer config helpers that\n * validate input eagerly and expose the normalized manifest JSON.\n */\nimport { buildAppManifest, buildPluginManifest } from \"../manifests/build\";\nimport type {\n AdminAppManifest,\n AppDefinition,\n PluginDefinition,\n PluginManifest,\n POSAppManifest,\n} from \"../manifests/types\";\n\nexport interface DefinedPlugin {\n readonly definition: PluginDefinition;\n readonly manifest: PluginManifest;\n /** The manifest JSON to PUT to the backend / publish. */\n toJSON(): PluginManifest;\n}\n\n/**\n * Validate a plugin definition and return a handle exposing its manifest.\n * Throws `ThreeuManifestError` if the definition is invalid.\n */\nexport function definePlugin(definition: PluginDefinition): DefinedPlugin {\n const manifest = buildPluginManifest(definition);\n return {\n definition,\n manifest,\n toJSON: () => manifest,\n };\n}\n\n/** Alias — some developers prefer `createPlugin`. */\nexport const createPlugin = definePlugin;\n\nexport interface DefinedApp {\n readonly definition: AppDefinition;\n readonly manifest: AdminAppManifest | POSAppManifest;\n toJSON(): AdminAppManifest | POSAppManifest;\n}\n\n/** Validate an admin/POS embedded-app definition and expose its manifest. */\nexport function defineApp(definition: AppDefinition): DefinedApp {\n const manifest = buildAppManifest(definition);\n return {\n definition,\n manifest,\n toJSON: () => manifest,\n };\n}\n"]}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { a as DefinedPlugin } from '../../define-B6ZJMWDI.js';
|
|
2
|
+
import '../../types-BoGD3IXz.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @threeu/threeu/plugin/server — remote plugin server helper. **EXPERIMENTAL.**
|
|
6
|
+
*
|
|
7
|
+
* Framework-agnostic: you register action + health handlers and expose `handle`
|
|
8
|
+
* (Web-standard request/response shape) or `fetchHandler` (a `Request`→`Response`
|
|
9
|
+
* function) behind your HTTP framework of choice.
|
|
10
|
+
*
|
|
11
|
+
* const app = createThreeuPluginServer({ plugin: fastShipPlugin, secret });
|
|
12
|
+
* app.action("shipping.get_rates", async ({ payload, brand }) => ({ rates: [...] }));
|
|
13
|
+
* app.health(() => ({ status: "ok", version: "1.0.0" }));
|
|
14
|
+
*
|
|
15
|
+
* Inbound calls from ThreeU are signature-verified (the backend signs the JSON
|
|
16
|
+
* body with `X-ThreeU-Signature` today — docs/ARCHITECTURE_MAP.md §4; the
|
|
17
|
+
* raw-body + `X-ThreeU-Timestamp` scheme is also accepted).
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
interface PluginServerRequest {
|
|
21
|
+
method: string;
|
|
22
|
+
path: string;
|
|
23
|
+
headers: Record<string, string>;
|
|
24
|
+
rawBody: string;
|
|
25
|
+
}
|
|
26
|
+
interface PluginServerResponse {
|
|
27
|
+
status: number;
|
|
28
|
+
headers: Record<string, string>;
|
|
29
|
+
body: string;
|
|
30
|
+
}
|
|
31
|
+
interface ActionContext {
|
|
32
|
+
action: string;
|
|
33
|
+
verb: string;
|
|
34
|
+
payload: Record<string, unknown>;
|
|
35
|
+
brand?: string | number;
|
|
36
|
+
install?: Record<string, unknown>;
|
|
37
|
+
settings?: Record<string, unknown>;
|
|
38
|
+
headers: Record<string, string>;
|
|
39
|
+
rawBody: string;
|
|
40
|
+
}
|
|
41
|
+
type ActionHandler = (ctx: ActionContext) => Promise<unknown> | unknown;
|
|
42
|
+
type HealthHandler = () => Promise<unknown> | unknown;
|
|
43
|
+
interface CreatePluginServerOptions {
|
|
44
|
+
plugin?: DefinedPlugin;
|
|
45
|
+
secret?: string;
|
|
46
|
+
/** Path that serves health checks. Default "/health". */
|
|
47
|
+
healthPath?: string;
|
|
48
|
+
/** Require a valid signature on action calls. Default true when `secret` set. */
|
|
49
|
+
requireSignature?: boolean;
|
|
50
|
+
}
|
|
51
|
+
declare class PluginServer {
|
|
52
|
+
private readonly handlers;
|
|
53
|
+
private healthHandler;
|
|
54
|
+
private readonly secret?;
|
|
55
|
+
private readonly healthPath;
|
|
56
|
+
private readonly requireSignature;
|
|
57
|
+
constructor(options?: CreatePluginServerOptions);
|
|
58
|
+
action(name: string, handler: ActionHandler): this;
|
|
59
|
+
health(handler: HealthHandler): this;
|
|
60
|
+
/** Registered action names — handy for tests and self-documentation. */
|
|
61
|
+
actionNames(): string[];
|
|
62
|
+
/** Core dispatch over a normalized request. */
|
|
63
|
+
handle(req: PluginServerRequest): Promise<PluginServerResponse>;
|
|
64
|
+
/** Web-standard `Request` → `Response` adapter for fetch-based servers. */
|
|
65
|
+
fetchHandler(request: Request): Promise<Response>;
|
|
66
|
+
private verify;
|
|
67
|
+
}
|
|
68
|
+
declare function createThreeuPluginServer(options?: CreatePluginServerOptions): PluginServer;
|
|
69
|
+
|
|
70
|
+
export { type ActionContext, type ActionHandler, type CreatePluginServerOptions, type HealthHandler, PluginServer, type PluginServerRequest, type PluginServerResponse, createThreeuPluginServer };
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { verifyWebhookSignature, verifyLegacyWebhook } from '../../chunk-ZWLFJIAM.js';
|
|
2
|
+
import '../../chunk-LFF5LPWT.js';
|
|
3
|
+
|
|
4
|
+
// src/plugin/server/index.ts
|
|
5
|
+
var PluginServer = class {
|
|
6
|
+
constructor(options = {}) {
|
|
7
|
+
this.handlers = /* @__PURE__ */ new Map();
|
|
8
|
+
this.healthHandler = () => ({ status: "ok" });
|
|
9
|
+
this.secret = options.secret;
|
|
10
|
+
this.healthPath = options.healthPath ?? "/health";
|
|
11
|
+
this.requireSignature = options.requireSignature ?? Boolean(options.secret);
|
|
12
|
+
}
|
|
13
|
+
action(name, handler) {
|
|
14
|
+
this.handlers.set(name, handler);
|
|
15
|
+
return this;
|
|
16
|
+
}
|
|
17
|
+
health(handler) {
|
|
18
|
+
this.healthHandler = handler;
|
|
19
|
+
return this;
|
|
20
|
+
}
|
|
21
|
+
/** Registered action names — handy for tests and self-documentation. */
|
|
22
|
+
actionNames() {
|
|
23
|
+
return Array.from(this.handlers.keys());
|
|
24
|
+
}
|
|
25
|
+
/** Core dispatch over a normalized request. */
|
|
26
|
+
async handle(req) {
|
|
27
|
+
const pathname = req.path.split("?")[0] ?? req.path;
|
|
28
|
+
if (pathname.endsWith(this.healthPath)) {
|
|
29
|
+
return json(200, await this.healthHandler());
|
|
30
|
+
}
|
|
31
|
+
let body = {};
|
|
32
|
+
if (req.rawBody) {
|
|
33
|
+
try {
|
|
34
|
+
body = JSON.parse(req.rawBody);
|
|
35
|
+
} catch {
|
|
36
|
+
return json(400, { error: "invalid_json" });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (this.requireSignature) {
|
|
40
|
+
const ok = await this.verify(req, body);
|
|
41
|
+
if (!ok) return json(401, { error: "invalid_signature" });
|
|
42
|
+
}
|
|
43
|
+
const action = resolveActionName(req, body);
|
|
44
|
+
const handler = action ? this.handlers.get(action) : void 0;
|
|
45
|
+
if (!action || !handler) {
|
|
46
|
+
return json(404, { error: "unknown_action", action });
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const result = await handler({
|
|
50
|
+
action,
|
|
51
|
+
verb: typeof body.verb === "string" ? body.verb : req.method,
|
|
52
|
+
payload: body.payload && typeof body.payload === "object" ? body.payload : body,
|
|
53
|
+
brand: body.brand_id ?? body.brand,
|
|
54
|
+
install: body.install,
|
|
55
|
+
settings: body.settings,
|
|
56
|
+
headers: req.headers,
|
|
57
|
+
rawBody: req.rawBody
|
|
58
|
+
});
|
|
59
|
+
return json(200, result ?? {});
|
|
60
|
+
} catch (err) {
|
|
61
|
+
return json(500, { error: "action_failed", message: err instanceof Error ? err.message : "unknown" });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** Web-standard `Request` → `Response` adapter for fetch-based servers. */
|
|
65
|
+
async fetchHandler(request) {
|
|
66
|
+
const url = new URL(request.url);
|
|
67
|
+
const rawBody = request.method === "GET" ? "" : await request.text();
|
|
68
|
+
const headers = {};
|
|
69
|
+
request.headers.forEach((v, k) => headers[k] = v);
|
|
70
|
+
const res = await this.handle({ method: request.method, path: url.pathname, headers, rawBody });
|
|
71
|
+
return new Response(res.body, { status: res.status, headers: res.headers });
|
|
72
|
+
}
|
|
73
|
+
async verify(req, body) {
|
|
74
|
+
if (!this.secret) return true;
|
|
75
|
+
const sig = header(req.headers, "x-threeu-signature") ?? header(req.headers, "x-plugin-signature");
|
|
76
|
+
if (!sig) return false;
|
|
77
|
+
const ts = header(req.headers, "x-threeu-timestamp") ?? header(req.headers, "x-plugin-timestamp");
|
|
78
|
+
if (ts) {
|
|
79
|
+
return verifyWebhookSignature({ secret: this.secret, rawBody: req.rawBody, timestamp: ts, signature: sig });
|
|
80
|
+
}
|
|
81
|
+
return verifyLegacyWebhook(this.secret, body, sig);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
function createThreeuPluginServer(options = {}) {
|
|
85
|
+
return new PluginServer(options);
|
|
86
|
+
}
|
|
87
|
+
function resolveActionName(req, body) {
|
|
88
|
+
if (typeof body.action === "string" && body.action) return body.action;
|
|
89
|
+
const segs = (req.path.split("?")[0] ?? "").split("/").filter(Boolean);
|
|
90
|
+
return segs.length ? segs[segs.length - 1] : void 0;
|
|
91
|
+
}
|
|
92
|
+
function header(headers, name) {
|
|
93
|
+
const target = name.toLowerCase();
|
|
94
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
95
|
+
if (k.toLowerCase() === target) return v;
|
|
96
|
+
}
|
|
97
|
+
return void 0;
|
|
98
|
+
}
|
|
99
|
+
function json(status, body) {
|
|
100
|
+
return { status, headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export { PluginServer, createThreeuPluginServer };
|
|
104
|
+
//# sourceMappingURL=index.js.map
|
|
105
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/plugin/server/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @threeu/threeu/plugin/server — remote plugin server helper. **EXPERIMENTAL.**\n *\n * Framework-agnostic: you register action + health handlers and expose `handle`\n * (Web-standard request/response shape) or `fetchHandler` (a `Request`→`Response`\n * function) behind your HTTP framework of choice.\n *\n * const app = createThreeuPluginServer({ plugin: fastShipPlugin, secret });\n * app.action(\"shipping.get_rates\", async ({ payload, brand }) => ({ rates: [...] }));\n * app.health(() => ({ status: \"ok\", version: \"1.0.0\" }));\n *\n * Inbound calls from ThreeU are signature-verified (the backend signs the JSON\n * body with `X-ThreeU-Signature` today — docs/ARCHITECTURE_MAP.md §4; the\n * raw-body + `X-ThreeU-Timestamp` scheme is also accepted).\n */\nimport type { DefinedPlugin } from \"../define\";\nimport { verifyLegacyWebhook, verifyWebhookSignature } from \"../../webhooks\";\n\nexport interface PluginServerRequest {\n method: string;\n path: string;\n headers: Record<string, string>;\n rawBody: string;\n}\n\nexport interface PluginServerResponse {\n status: number;\n headers: Record<string, string>;\n body: string;\n}\n\nexport interface ActionContext {\n action: string;\n verb: string;\n payload: Record<string, unknown>;\n brand?: string | number;\n install?: Record<string, unknown>;\n settings?: Record<string, unknown>;\n headers: Record<string, string>;\n rawBody: string;\n}\n\nexport type ActionHandler = (ctx: ActionContext) => Promise<unknown> | unknown;\nexport type HealthHandler = () => Promise<unknown> | unknown;\n\nexport interface CreatePluginServerOptions {\n plugin?: DefinedPlugin;\n secret?: string;\n /** Path that serves health checks. Default \"/health\". */\n healthPath?: string;\n /** Require a valid signature on action calls. Default true when `secret` set. */\n requireSignature?: boolean;\n}\n\nexport class PluginServer {\n private readonly handlers = new Map<string, ActionHandler>();\n private healthHandler: HealthHandler = () => ({ status: \"ok\" });\n private readonly secret?: string;\n private readonly healthPath: string;\n private readonly requireSignature: boolean;\n\n constructor(options: CreatePluginServerOptions = {}) {\n this.secret = options.secret;\n this.healthPath = options.healthPath ?? \"/health\";\n this.requireSignature = options.requireSignature ?? Boolean(options.secret);\n }\n\n action(name: string, handler: ActionHandler): this {\n this.handlers.set(name, handler);\n return this;\n }\n\n health(handler: HealthHandler): this {\n this.healthHandler = handler;\n return this;\n }\n\n /** Registered action names — handy for tests and self-documentation. */\n actionNames(): string[] {\n return Array.from(this.handlers.keys());\n }\n\n /** Core dispatch over a normalized request. */\n async handle(req: PluginServerRequest): Promise<PluginServerResponse> {\n const pathname = req.path.split(\"?\")[0] ?? req.path;\n\n if (pathname.endsWith(this.healthPath)) {\n return json(200, await this.healthHandler());\n }\n\n let body: Record<string, unknown> = {};\n if (req.rawBody) {\n try {\n body = JSON.parse(req.rawBody) as Record<string, unknown>;\n } catch {\n return json(400, { error: \"invalid_json\" });\n }\n }\n\n if (this.requireSignature) {\n const ok = await this.verify(req, body);\n if (!ok) return json(401, { error: \"invalid_signature\" });\n }\n\n const action = resolveActionName(req, body);\n const handler = action ? this.handlers.get(action) : undefined;\n if (!action || !handler) {\n return json(404, { error: \"unknown_action\", action });\n }\n\n try {\n const result = await handler({\n action,\n verb: typeof body.verb === \"string\" ? body.verb : req.method,\n payload: (body.payload && typeof body.payload === \"object\" ? body.payload : body) as Record<string, unknown>,\n brand: (body.brand_id as string | number) ?? (body.brand as string | number),\n install: body.install as Record<string, unknown> | undefined,\n settings: body.settings as Record<string, unknown> | undefined,\n headers: req.headers,\n rawBody: req.rawBody,\n });\n return json(200, result ?? {});\n } catch (err) {\n return json(500, { error: \"action_failed\", message: err instanceof Error ? err.message : \"unknown\" });\n }\n }\n\n /** Web-standard `Request` → `Response` adapter for fetch-based servers. */\n async fetchHandler(request: Request): Promise<Response> {\n const url = new URL(request.url);\n const rawBody = request.method === \"GET\" ? \"\" : await request.text();\n const headers: Record<string, string> = {};\n request.headers.forEach((v, k) => (headers[k] = v));\n const res = await this.handle({ method: request.method, path: url.pathname, headers, rawBody });\n return new Response(res.body, { status: res.status, headers: res.headers });\n }\n\n private async verify(req: PluginServerRequest, body: Record<string, unknown>): Promise<boolean> {\n if (!this.secret) return true;\n const sig =\n header(req.headers, \"x-threeu-signature\") ?? header(req.headers, \"x-plugin-signature\");\n if (!sig) return false;\n const ts = header(req.headers, \"x-threeu-timestamp\") ?? header(req.headers, \"x-plugin-timestamp\");\n if (ts) {\n return verifyWebhookSignature({ secret: this.secret, rawBody: req.rawBody, timestamp: ts, signature: sig });\n }\n // Legacy: backend signs json_encode(body) with no timestamp.\n return verifyLegacyWebhook(this.secret, body, sig);\n }\n}\n\nexport function createThreeuPluginServer(options: CreatePluginServerOptions = {}): PluginServer {\n return new PluginServer(options);\n}\n\nfunction resolveActionName(req: PluginServerRequest, body: Record<string, unknown>): string | undefined {\n if (typeof body.action === \"string\" && body.action) return body.action;\n const segs = (req.path.split(\"?\")[0] ?? \"\").split(\"/\").filter(Boolean);\n return segs.length ? segs[segs.length - 1] : undefined;\n}\n\nfunction header(headers: Record<string, string>, name: string): string | undefined {\n const target = name.toLowerCase();\n for (const [k, v] of Object.entries(headers)) {\n if (k.toLowerCase() === target) return v;\n }\n return undefined;\n}\n\nfunction json(status: number, body: unknown): PluginServerResponse {\n return { status, headers: { \"Content-Type\": \"application/json\" }, body: JSON.stringify(body) };\n}\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { T as ThreeuHttpClient, i as ThreeuClientOptions } from '../types-DfyYnoLn.js';
|
|
2
|
+
import { P as PosSessionConfig, a as PosSession } from '../session-BFDRm-KJ.js';
|
|
3
|
+
export { C as CartData, b as CartDiscountInput, c as CartItemInput, d as CheckoutInput, e as PosCart, f as PosCartNamespace, g as PosNamespace } from '../session-BFDRm-KJ.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @threeu/threeu/pos — POS client.
|
|
7
|
+
*
|
|
8
|
+
* const pos = new ThreeuPOS(token, { brand: "brand-slug" });
|
|
9
|
+
* const session = pos.session({ locationId: "location_123", cashierId: "user_123" });
|
|
10
|
+
* const cart = await session.cart.create();
|
|
11
|
+
* await cart.addItem({ productId: "prod_123", quantity: 2 });
|
|
12
|
+
* await cart.applyDiscount({ type: "percentage", value: 10 });
|
|
13
|
+
* const payment = await cart.checkout({ method: "card" });
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
type ThreeuPOSOptions = Omit<ThreeuClientOptions, "token" | "tokenType">;
|
|
17
|
+
declare class ThreeuPOS {
|
|
18
|
+
readonly http: ThreeuHttpClient;
|
|
19
|
+
private readonly pos;
|
|
20
|
+
private readonly brand?;
|
|
21
|
+
constructor(token: string, options?: ThreeuPOSOptions);
|
|
22
|
+
session(config?: PosSessionConfig): PosSession;
|
|
23
|
+
close(): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { PosSession, PosSessionConfig, ThreeuPOS, type ThreeuPOSOptions };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { PosNamespace } from '../chunk-BCUODRZW.js';
|
|
2
|
+
export { PosCart, PosCartNamespace, PosNamespace, PosSession } from '../chunk-BCUODRZW.js';
|
|
3
|
+
import { ThreeuHttpClient } from '../chunk-HYSJ6YPN.js';
|
|
4
|
+
import '../chunk-H3XILKGI.js';
|
|
5
|
+
import '../chunk-LFF5LPWT.js';
|
|
6
|
+
|
|
7
|
+
// src/pos/index.ts
|
|
8
|
+
var ThreeuPOS = class {
|
|
9
|
+
constructor(token, options = {}) {
|
|
10
|
+
this.brand = options.brand;
|
|
11
|
+
this.http = new ThreeuHttpClient({ ...options, token, tokenType: "pos" });
|
|
12
|
+
this.pos = new PosNamespace({ http: this.http, brand: this.brand });
|
|
13
|
+
}
|
|
14
|
+
session(config) {
|
|
15
|
+
return this.pos.session(config);
|
|
16
|
+
}
|
|
17
|
+
close() {
|
|
18
|
+
return this.http.close();
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export { ThreeuPOS };
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
24
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/pos/index.ts"],"names":[],"mappings":";;;;;;;AAiBO,IAAM,YAAN,MAAgB;AAAA,EAKrB,WAAA,CAAY,KAAA,EAAe,OAAA,GAA4B,EAAC,EAAG;AACzD,IAAA,IAAA,CAAK,QAAQ,OAAA,CAAQ,KAAA;AACrB,IAAA,IAAA,CAAK,IAAA,GAAO,IAAI,gBAAA,CAAiB,EAAE,GAAG,OAAA,EAAS,KAAA,EAAO,SAAA,EAAW,KAAA,EAAO,CAAA;AACxE,IAAA,IAAA,CAAK,GAAA,GAAM,IAAI,YAAA,CAAa,EAAE,IAAA,EAAM,KAAK,IAAA,EAAM,KAAA,EAAO,IAAA,CAAK,KAAA,EAAO,CAAA;AAAA,EACpE;AAAA,EAEA,QAAQ,MAAA,EAAuC;AAC7C,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,OAAA,CAAQ,MAAM,CAAA;AAAA,EAChC;AAAA,EAEA,KAAA,GAAuB;AACrB,IAAA,OAAO,IAAA,CAAK,KAAK,KAAA,EAAM;AAAA,EACzB;AACF","file":"index.js","sourcesContent":["/**\n * @threeu/threeu/pos — POS client.\n *\n * const pos = new ThreeuPOS(token, { brand: \"brand-slug\" });\n * const session = pos.session({ locationId: \"location_123\", cashierId: \"user_123\" });\n * const cart = await session.cart.create();\n * await cart.addItem({ productId: \"prod_123\", quantity: 2 });\n * await cart.applyDiscount({ type: \"percentage\", value: 10 });\n * const payment = await cart.checkout({ method: \"card\" });\n */\nimport { ThreeuHttpClient } from \"../core/http-client\";\nimport type { ThreeuClientOptions } from \"../core/types\";\nimport type { Id } from \"../resources/types\";\nimport { PosNamespace, PosSession, type PosSessionConfig } from \"./session\";\n\nexport type ThreeuPOSOptions = Omit<ThreeuClientOptions, \"token\" | \"tokenType\">;\n\nexport class ThreeuPOS {\n readonly http: ThreeuHttpClient;\n private readonly pos: PosNamespace;\n private readonly brand?: Id;\n\n constructor(token: string, options: ThreeuPOSOptions = {}) {\n this.brand = options.brand;\n this.http = new ThreeuHttpClient({ ...options, token, tokenType: \"pos\" });\n this.pos = new PosNamespace({ http: this.http, brand: this.brand });\n }\n\n session(config?: PosSessionConfig): PosSession {\n return this.pos.session(config);\n }\n\n close(): Promise<void> {\n return this.http.close();\n }\n}\n\nexport {\n PosNamespace,\n PosSession,\n PosCart,\n PosCartNamespace,\n} from \"./session\";\nexport type {\n PosSessionConfig,\n CartItemInput,\n CartDiscountInput,\n CheckoutInput,\n CartData,\n} from \"./session\";\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { A as AsyncState, T as ThemeBrandInfo, a as ThemeContextValue, b as ThemeProvider, c as ThemeProviderProps, d as ThreeuThemeProvider, e as ThreeuThemeProviderProps, u as useBrand, i as useCart, j as useCheckout, k as useCollections, l as useCurrency, m as useCustomer, n as useLocale, o as useProducts, p as useTheme, q as useThemeContext, t as useThemeField } from '../index-ksmDFDZc.js';
|
|
2
|
+
import 'react';
|
|
3
|
+
import '../storefront/index.js';
|
|
4
|
+
import '../types-DfyYnoLn.js';
|
|
5
|
+
import '../types-BoGD3IXz.js';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { ThemeProvider, ThreeuThemeProvider, useBrand, useCart, useCheckout, useCollections, useCurrency, useCustomer, useLocale, useProducts, useTheme, useThemeContext, useThemeField } from '../chunk-6ZCBDWWQ.js';
|
|
2
|
+
import '../chunk-6S7OFN23.js';
|
|
3
|
+
import '../chunk-HYSJ6YPN.js';
|
|
4
|
+
import '../chunk-H3XILKGI.js';
|
|
5
|
+
import '../chunk-LFF5LPWT.js';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|