shipos 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,225 @@
1
+ # @shipos/sdk
2
+
3
+ Official SDK for ShipOS feature flags, global configs, and customer identification.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ bun add @shipos/sdk
9
+ # or
10
+ npm install @shipos/sdk
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ### Basic Usage (Vanilla JS/TS)
16
+
17
+ ```typescript
18
+ import { createShipOS } from '@shipos/sdk';
19
+
20
+ const shipos = createShipOS({
21
+ apiKey: 'your-api-key',
22
+ environment: 'production', // optional, defaults to 'production'
23
+ });
24
+
25
+ // Identify a customer
26
+ await shipos.customers.signIn({
27
+ externalId: 'user-123',
28
+ metadata: { name: 'Jane', plan: 'pro' },
29
+ });
30
+
31
+ // Get all feature flags
32
+ const flags = await shipos.featureFlags.getAll();
33
+ console.log(flags); // { 'new-feature': true, 'beta-mode': false }
34
+
35
+ // Get a single flag with default value
36
+ const isEnabled = await shipos.featureFlags.get('new-feature', false);
37
+
38
+ // Get a typed config
39
+ interface PricingConfig {
40
+ plans: Array<{ name: string; price: number }>;
41
+ }
42
+ const pricing = await shipos.configs.get<PricingConfig>('pricing');
43
+ ```
44
+
45
+ ### React Integration
46
+
47
+ ```tsx
48
+ import { ShipOSProvider, useFlag, useCustomer, Feature } from '@shipos/sdk/react';
49
+
50
+ // Wrap your app with the provider
51
+ function App() {
52
+ return (
53
+ <ShipOSProvider config={{ apiKey: 'your-api-key' }}>
54
+ <MyApp />
55
+ </ShipOSProvider>
56
+ );
57
+ }
58
+
59
+ // Identify users with useCustomer
60
+ function MyApp() {
61
+ const { signIn } = useCustomer();
62
+
63
+ useEffect(() => {
64
+ signIn({ externalId: 'user-123', metadata: { plan: 'pro' } });
65
+ }, []);
66
+
67
+ return <Dashboard />;
68
+ }
69
+
70
+ // Use hooks in your components
71
+ function Dashboard() {
72
+ const { enabled, isLoading } = useFlag('new-feature');
73
+
74
+ if (isLoading) return <div>Loading...</div>;
75
+
76
+ return enabled ? <NewFeature /> : <OldFeature />;
77
+ }
78
+
79
+ // Or use the Feature component
80
+ function AnotherComponent() {
81
+ return (
82
+ <Feature flag="new-dashboard" fallback={<OldDashboard />}>
83
+ <NewDashboard />
84
+ </Feature>
85
+ );
86
+ }
87
+ ```
88
+
89
+ ## API Reference
90
+
91
+ ### Core Client
92
+
93
+ #### `createShipOS(config)`
94
+
95
+ Creates a new ShipOS client instance.
96
+
97
+ ```typescript
98
+ const shipos = createShipOS({
99
+ apiKey: string; // Required: Your API key
100
+ baseUrl?: string; // Optional: API base URL
101
+ environment?: string; // Optional: Environment (default: 'production')
102
+ cacheTTL?: number; // Optional: Cache TTL in ms (default: 60000)
103
+ debug?: boolean; // Optional: Enable debug logging
104
+ });
105
+ ```
106
+
107
+ ### Customers
108
+
109
+ - `customers.signIn({ externalId, metadata? })` - Identify a customer
110
+ - `customers.signOut()` - Clear customer context
111
+ - `customers.get()` - Get current customer or null
112
+
113
+ ### Feature Flags
114
+
115
+ - `featureFlags.getAll()` - Get all feature flags
116
+ - `featureFlags.get(key, defaultValue?)` - Get a single flag
117
+ - `featureFlags.refresh()` - Refresh flags (bypass cache)
118
+
119
+ ### Global Configs
120
+
121
+ - `configs.get<T>(slug)` - Get a config by slug
122
+ - `configs.refresh<T>(slug)` - Refresh a config (bypass cache)
123
+
124
+ ### Utilities
125
+
126
+ - `clearCache()` - Clear the cache
127
+ - `setEnvironment(env)` - Change environment
128
+ - `getEnvironment()` - Get current environment
129
+
130
+ ### React Hooks
131
+
132
+ #### `useCustomer()`
133
+
134
+ Manage customer identification.
135
+
136
+ ```typescript
137
+ const { customer, signIn, signOut } = useCustomer();
138
+ ```
139
+
140
+ #### `useFlags()`
141
+
142
+ Get all feature flags.
143
+
144
+ ```typescript
145
+ const { flags, isLoading, error, refreshFlags } = useFlags();
146
+ ```
147
+
148
+ #### `useFlag(key, defaultValue?)`
149
+
150
+ Get a single feature flag.
151
+
152
+ ```typescript
153
+ const { enabled, isLoading, error } = useFlag('my-feature', false);
154
+ ```
155
+
156
+ #### `useConfig<T>(slug)`
157
+
158
+ Get a configuration by slug.
159
+
160
+ ```typescript
161
+ const { config, isLoading, error, refresh } = useConfig<MyConfig>('my-config');
162
+ ```
163
+
164
+ ### React Components
165
+
166
+ #### `<Feature>`
167
+
168
+ Conditionally render based on a flag.
169
+
170
+ ```tsx
171
+ <Feature flag="my-feature" fallback={<Fallback />} loading={<Loading />}>
172
+ <EnabledContent />
173
+ </Feature>
174
+ ```
175
+
176
+ #### `<FeatureEnabled>`
177
+
178
+ Render only when flag is enabled.
179
+
180
+ ```tsx
181
+ <FeatureEnabled flag="my-feature">
182
+ <EnabledContent />
183
+ </FeatureEnabled>
184
+ ```
185
+
186
+ #### `<FeatureDisabled>`
187
+
188
+ Render only when flag is disabled.
189
+
190
+ ```tsx
191
+ <FeatureDisabled flag="my-feature">
192
+ <DisabledContent />
193
+ </FeatureDisabled>
194
+ ```
195
+
196
+ ## Configuration
197
+
198
+ ### Environment Variables
199
+
200
+ You can configure the SDK using environment variables:
201
+
202
+ ```bash
203
+ SHIPOS_API_KEY=your-api-key
204
+ SHIPOS_ENVIRONMENT=production
205
+ SHIPOS_BASE_URL=https://api.shipos.app
206
+ ```
207
+
208
+ ### Server-Side Rendering (SSR)
209
+
210
+ For SSR, you can pass initial flags to avoid loading states:
211
+
212
+ ```tsx
213
+ // In your server component or getServerSideProps
214
+ const shipos = createShipOS({ apiKey: process.env.SHIPOS_API_KEY });
215
+ const initialFlags = await shipos.featureFlags.getAll();
216
+
217
+ // Pass to provider
218
+ <ShipOSProvider config={config} initialFlags={initialFlags}>
219
+ <App />
220
+ </ShipOSProvider>
221
+ ```
222
+
223
+ ## License
224
+
225
+ MIT
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Simple in-memory cache for SDK responses
3
+ */
4
+ export declare class Cache {
5
+ private store;
6
+ private defaultTTL;
7
+ constructor(defaultTTL?: number);
8
+ /**
9
+ * Get a value from the cache
10
+ */
11
+ get<T>(key: string): T | null;
12
+ /**
13
+ * Set a value in the cache
14
+ */
15
+ set<T>(key: string, data: T): void;
16
+ /**
17
+ * Delete a value from the cache
18
+ */
19
+ delete(key: string): void;
20
+ /**
21
+ * Clear all cached values
22
+ */
23
+ clear(): void;
24
+ /**
25
+ * Update the default TTL
26
+ */
27
+ setTTL(ttl: number): void;
28
+ }
29
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,qBAAa,KAAK;IAChB,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,UAAU,CAAS;gBAEf,UAAU,GAAE,MAAc;IAItC;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IAgB7B;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI;IAOlC;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;CAG1B"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * ShipOS SDK Client
3
+ *
4
+ * Main client for interacting with the ShipOS API.
5
+ * Methods are organized into namespaced modules:
6
+ * - `featureFlags` - Feature flag operations
7
+ * - `configs` - Global config operations
8
+ * - `customers` - Customer identification
9
+ */
10
+ import { FeatureFlagsModule } from "./modules/feature-flags";
11
+ import { ConfigsModule } from "./modules/configs";
12
+ import { CustomersModule } from "./modules/customers";
13
+ import type { ShipOSConfig } from "./types";
14
+ export declare class ShipOS {
15
+ private apiKey;
16
+ private baseUrl;
17
+ private environment;
18
+ private cache;
19
+ private debug;
20
+ private customerId;
21
+ /** Feature flag operations */
22
+ readonly featureFlags: FeatureFlagsModule;
23
+ /** Global config operations */
24
+ readonly configs: ConfigsModule;
25
+ /** Customer identification */
26
+ readonly customers: CustomersModule;
27
+ constructor(config: ShipOSConfig);
28
+ /**
29
+ * Log debug messages
30
+ */
31
+ private log;
32
+ /**
33
+ * Make an authenticated request to the API
34
+ */
35
+ private request;
36
+ /**
37
+ * Clear the cache
38
+ */
39
+ clearCache(): void;
40
+ /**
41
+ * Update the environment
42
+ */
43
+ setEnvironment(environment: string): void;
44
+ /**
45
+ * Get current environment
46
+ */
47
+ getEnvironment(): string;
48
+ }
49
+ /**
50
+ * Create a new ShipOS client instance
51
+ */
52
+ export declare function createShipOS(config: ShipOSConfig): ShipOS;
53
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAY,MAAM,SAAS,CAAC;AAMtD,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,KAAK,CAAU;IACvB,OAAO,CAAC,UAAU,CAAuB;IAEzC,8BAA8B;IAC9B,QAAQ,CAAC,YAAY,EAAE,kBAAkB,CAAC;IAC1C,+BAA+B;IAC/B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,8BAA8B;IAC9B,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;gBAExB,MAAM,EAAE,YAAY;IA2BhC;;OAEG;IACH,OAAO,CAAC,GAAG;IAMX;;OAEG;YACW,OAAO;IAsCrB;;OAEG;IACH,UAAU,IAAI,IAAI;IAKlB;;OAEG;IACH,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAMzC;;OAEG;IACH,cAAc,IAAI,MAAM;CAGzB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAEzD"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * ShipOS SDK
3
+ *
4
+ * Official SDK for ShipOS feature flags, global configs, and customer identification.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { createShipOS } from '@shipos/sdk';
9
+ *
10
+ * const shipos = createShipOS({
11
+ * apiKey: 'your-api-key',
12
+ * environment: 'production',
13
+ * });
14
+ *
15
+ * // Identify a customer
16
+ * await shipos.customers.signIn({ externalId: 'user-123', metadata: { plan: 'pro' } });
17
+ *
18
+ * // Get all flags
19
+ * const flags = await shipos.featureFlags.getAll();
20
+ *
21
+ * // Get a single flag
22
+ * const isEnabled = await shipos.featureFlags.get('new-feature', false);
23
+ *
24
+ * // Get a config
25
+ * const pricing = await shipos.configs.get('pricing');
26
+ * ```
27
+ */
28
+ export { ShipOS, createShipOS } from "./client";
29
+ export { Cache } from "./cache";
30
+ export type { ShipOSConfig, FlagsResponse, ConfigResponse, ApiError, CacheEntry, Result, CustomerInfo, SignInOptions, } from "./types";
31
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,YAAY,EACV,YAAY,EACZ,aAAa,EACb,cAAc,EACd,QAAQ,EACR,UAAU,EACV,MAAM,EACN,YAAY,EACZ,aAAa,GACd,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ class b{store=new Map;defaultTTL;constructor(S=60000){this.defaultTTL=S}get(S){let O=this.store.get(S);if(!O)return null;if(Date.now()-O.timestamp>this.defaultTTL)return this.store.delete(S),null;return O.data}set(S,O){this.store.set(S,{data:O,timestamp:Date.now()})}delete(S){this.store.delete(S)}clear(){this.store.clear()}setTTL(S){this.defaultTTL=S}}class j{ctx;constructor(S){this.ctx=S}async getAll(){let S=`flags:${this.ctx.getEnvironment()}`,O=this.ctx.cache.get(S);if(O)return this.ctx.log("Returning cached flags"),O;let w=await this.ctx.request("/v1/flags");return this.ctx.cache.set(S,w),w}async get(S,O=!1){return(await this.getAll())[S]??O}async refresh(){let S=`flags:${this.ctx.getEnvironment()}`;return this.ctx.cache.delete(S),this.getAll()}}class q{ctx;constructor(S){this.ctx=S}async get(S){let O=`config:${this.ctx.getEnvironment()}:${S}`,w=this.ctx.cache.get(O);if(w)return this.ctx.log(`Returning cached config: ${S}`),w;let G=await this.ctx.request(`/v1/config/${S}`);return this.ctx.cache.set(O,G),G}async refresh(S){let O=`config:${this.ctx.getEnvironment()}:${S}`;return this.ctx.cache.delete(O),this.get(S)}}class z{ctx;customer=null;constructor(S){this.ctx=S}async signIn(S){if(!S.externalId)throw Error("ShipOS: externalId is required for signIn");return this.ctx.log(`Signing in customer: ${S.externalId}`),this.customer={externalId:S.externalId,metadata:S.metadata},this.ctx.setCustomerId(S.externalId),await this.ctx.request("/v1/customers/identify",{method:"POST",body:{externalId:S.externalId,metadata:S.metadata??{}}}),this.ctx.log(`Customer signed in: ${S.externalId}`),this.customer}signOut(){this.ctx.log("Signing out customer"),this.customer=null,this.ctx.setCustomerId(null)}get(){return this.customer}}var Y="https://api.shipos.app",Z=60000,B="0.1.0";class J{apiKey;baseUrl;environment;cache;debug;customerId=null;featureFlags;configs;customers;constructor(S){if(!S.apiKey)throw Error("ShipOS: apiKey is required");this.apiKey=S.apiKey,this.baseUrl=S.baseUrl||Y,this.environment=S.environment||"production",this.cache=new b(S.cacheTTL||Z),this.debug=S.debug||!1;let O={request:this.request.bind(this),cache:this.cache,getEnvironment:this.getEnvironment.bind(this),log:this.log.bind(this),setCustomerId:(w)=>{this.customerId=w}};this.featureFlags=new j(O),this.configs=new q(O),this.customers=new z(O)}log(...S){if(this.debug)console.log("[ShipOS]",...S)}async request(S,O={}){let w=`${this.baseUrl}${S}`,G=O.method||"GET";this.log(`${G} ${w}`);let Q={"x-shipos-key":this.apiKey,"x-shipos-env":this.environment,"x-shipos-sdk-version":B,"Content-Type":"application/json"};if(this.customerId)Q["x-shipos-customer-id"]=this.customerId;let W={method:G,headers:Q};if(O.body&&G!=="GET")W.body=JSON.stringify(O.body);let I=await fetch(w,W);if(!I.ok){let X=await I.json().catch(()=>({error:`HTTP ${I.status}`,code:"HTTP_ERROR"}));throw Error(X.error||`Request failed: ${I.status}`)}return I.json()}clearCache(){this.cache.clear(),this.log("Cache cleared")}setEnvironment(S){this.environment=S,this.cache.clear(),this.log(`Environment changed to: ${S}`)}getEnvironment(){return this.environment}}function D(S){return new J(S)}export{D as createShipOS,J as ShipOS,b as Cache};
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Configs Module
3
+ *
4
+ * Provides namespaced access to global configuration operations.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * const pricing = await shipos.configs.get<PricingConfig>('pricing');
9
+ * ```
10
+ */
11
+ import type { Cache } from "../cache";
12
+ import type { ConfigResponse } from "../types";
13
+ /**
14
+ * Internal context shared by the parent ShipOS client
15
+ */
16
+ export interface ConfigsContext {
17
+ request: <T>(endpoint: string, options?: {
18
+ method?: string;
19
+ body?: unknown;
20
+ }) => Promise<T>;
21
+ cache: Cache;
22
+ getEnvironment: () => string;
23
+ log: (...args: unknown[]) => void;
24
+ }
25
+ export declare class ConfigsModule {
26
+ private ctx;
27
+ constructor(ctx: ConfigsContext);
28
+ /**
29
+ * Get a configuration by slug
30
+ *
31
+ * @param slug - The config slug
32
+ * @returns The config data
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * interface PricingConfig {
37
+ * plans: Array<{ name: string; price: number }>;
38
+ * }
39
+ * const pricing = await shipos.configs.get<PricingConfig>('pricing');
40
+ * ```
41
+ */
42
+ get<T = Record<string, unknown>>(slug: string): Promise<ConfigResponse<T>>;
43
+ /**
44
+ * Refresh a config (bypass cache)
45
+ *
46
+ * @param slug - The config slug
47
+ * @returns Fresh config from the API
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * const freshConfig = await shipos.configs.refresh<PricingConfig>('pricing');
52
+ * ```
53
+ */
54
+ refresh<T = Record<string, unknown>>(slug: string): Promise<ConfigResponse<T>>;
55
+ }
56
+ //# sourceMappingURL=configs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configs.d.ts","sourceRoot":"","sources":["../../src/modules/configs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAC5F,KAAK,EAAE,KAAK,CAAC;IACb,cAAc,EAAE,MAAM,MAAM,CAAC;IAC7B,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;CACnC;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,GAAG,CAAiB;gBAEhB,GAAG,EAAE,cAAc;IAI/B;;;;;;;;;;;;;OAaG;IACG,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;IAchF;;;;;;;;;;OAUG;IACG,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;CAKrF"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Customers Module
3
+ *
4
+ * Provides customer identification (sign-in) for the ShipOS SDK.
5
+ * When a customer is signed in, their external ID is sent with
6
+ * subsequent API requests for targeting and analytics.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * await shipos.customers.signIn({ externalId: 'user-123', metadata: { plan: 'pro' } });
11
+ * const customer = shipos.customers.get();
12
+ * shipos.customers.signOut();
13
+ * ```
14
+ */
15
+ import type { CustomerInfo, SignInOptions } from "../types";
16
+ /**
17
+ * Internal context shared by the parent ShipOS client
18
+ */
19
+ export interface CustomersContext {
20
+ request: <T>(endpoint: string, options?: {
21
+ method?: string;
22
+ body?: unknown;
23
+ }) => Promise<T>;
24
+ log: (...args: unknown[]) => void;
25
+ setCustomerId: (id: string | null) => void;
26
+ }
27
+ export declare class CustomersModule {
28
+ private ctx;
29
+ private customer;
30
+ constructor(ctx: CustomersContext);
31
+ /**
32
+ * Sign in a customer
33
+ *
34
+ * Identifies the customer by their external ID and optional metadata.
35
+ * The customer context is stored locally and sent to the API for
36
+ * tracking and future flag targeting.
37
+ *
38
+ * @param options - Sign-in options with externalId and optional metadata
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * await shipos.customers.signIn({
43
+ * externalId: 'user-123',
44
+ * metadata: { name: 'John', plan: 'pro' },
45
+ * });
46
+ * ```
47
+ */
48
+ signIn(options: SignInOptions): Promise<CustomerInfo>;
49
+ /**
50
+ * Sign out the current customer
51
+ *
52
+ * Clears the local customer context. Subsequent API requests
53
+ * will no longer include customer identification.
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * shipos.customers.signOut();
58
+ * ```
59
+ */
60
+ signOut(): void;
61
+ /**
62
+ * Get the current signed-in customer
63
+ *
64
+ * @returns The current customer info, or null if no customer is signed in
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * const customer = shipos.customers.get();
69
+ * if (customer) {
70
+ * console.log(`Signed in as: ${customer.externalId}`);
71
+ * }
72
+ * ```
73
+ */
74
+ get(): CustomerInfo | null;
75
+ }
76
+ //# sourceMappingURL=customers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customers.d.ts","sourceRoot":"","sources":["../../src/modules/customers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAC5F,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IAClC,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAC5C;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,GAAG,CAAmB;IAC9B,OAAO,CAAC,QAAQ,CAA6B;gBAEjC,GAAG,EAAE,gBAAgB;IAIjC;;;;;;;;;;;;;;;;OAgBG;IACG,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IA6B3D;;;;;;;;;;OAUG;IACH,OAAO,IAAI,IAAI;IAMf;;;;;;;;;;;;OAYG;IACH,GAAG,IAAI,YAAY,GAAG,IAAI;CAG3B"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Feature Flags Module
3
+ *
4
+ * Provides namespaced access to feature flag operations.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * const flags = await shipos.featureFlags.getAll();
9
+ * const isEnabled = await shipos.featureFlags.get('new-feature', false);
10
+ * ```
11
+ */
12
+ import type { Cache } from "../cache";
13
+ import type { FlagsResponse } from "../types";
14
+ /**
15
+ * Internal context shared by the parent ShipOS client
16
+ */
17
+ export interface FeatureFlagsContext {
18
+ request: <T>(endpoint: string, options?: {
19
+ method?: string;
20
+ body?: unknown;
21
+ }) => Promise<T>;
22
+ cache: Cache;
23
+ getEnvironment: () => string;
24
+ log: (...args: unknown[]) => void;
25
+ }
26
+ export declare class FeatureFlagsModule {
27
+ private ctx;
28
+ constructor(ctx: FeatureFlagsContext);
29
+ /**
30
+ * Get all feature flags
31
+ *
32
+ * @returns Record of flag keys to boolean values
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * const flags = await shipos.featureFlags.getAll();
37
+ * // => { "new-dashboard": true, "beta-features": false }
38
+ * ```
39
+ */
40
+ getAll(): Promise<FlagsResponse>;
41
+ /**
42
+ * Get a single feature flag value
43
+ *
44
+ * @param key - The flag key
45
+ * @param defaultValue - Default value if flag is not found (defaults to false)
46
+ * @returns The flag value or default
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * const isEnabled = await shipos.featureFlags.get('new-dashboard', false);
51
+ * ```
52
+ */
53
+ get(key: string, defaultValue?: boolean): Promise<boolean>;
54
+ /**
55
+ * Refresh flags (bypass cache)
56
+ *
57
+ * @returns Fresh flags from the API
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * const freshFlags = await shipos.featureFlags.refresh();
62
+ * ```
63
+ */
64
+ refresh(): Promise<FlagsResponse>;
65
+ }
66
+ //# sourceMappingURL=feature-flags.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-flags.d.ts","sourceRoot":"","sources":["../../src/modules/feature-flags.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAC5F,KAAK,EAAE,KAAK,CAAC;IACb,cAAc,EAAE,MAAM,MAAM,CAAC;IAC7B,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;CACnC;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,GAAG,CAAsB;gBAErB,GAAG,EAAE,mBAAmB;IAIpC;;;;;;;;;;OAUG;IACG,MAAM,IAAI,OAAO,CAAC,aAAa,CAAC;IActC;;;;;;;;;;;OAWG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,GAAE,OAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IAKvE;;;;;;;;;OASG;IACG,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC;CAKxC"}
@@ -0,0 +1,85 @@
1
+ import type { ReactNode } from "react";
2
+ /**
3
+ * Feature Component Props
4
+ */
5
+ interface FeatureProps {
6
+ /** The feature flag key */
7
+ flag: string;
8
+ /** Content to render when the flag is enabled */
9
+ children: ReactNode;
10
+ /** Content to render when the flag is disabled (optional) */
11
+ fallback?: ReactNode;
12
+ /** Content to render while loading (optional) */
13
+ loading?: ReactNode;
14
+ }
15
+ /**
16
+ * Feature Component
17
+ *
18
+ * Conditionally renders content based on a feature flag.
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * // Basic usage
23
+ * <Feature flag="new-dashboard">
24
+ * <NewDashboard />
25
+ * </Feature>
26
+ *
27
+ * // With fallback
28
+ * <Feature flag="new-dashboard" fallback={<OldDashboard />}>
29
+ * <NewDashboard />
30
+ * </Feature>
31
+ *
32
+ * // With loading state
33
+ * <Feature flag="new-dashboard" loading={<Skeleton />}>
34
+ * <NewDashboard />
35
+ * </Feature>
36
+ * ```
37
+ */
38
+ export declare function Feature({ flag, children, fallback, loading, }: FeatureProps): import("react/jsx-runtime").JSX.Element;
39
+ /**
40
+ * FeatureEnabled Component Props
41
+ */
42
+ interface FeatureEnabledProps {
43
+ /** The feature flag key */
44
+ flag: string;
45
+ /** Content to render when the flag is enabled */
46
+ children: ReactNode;
47
+ }
48
+ /**
49
+ * FeatureEnabled Component
50
+ *
51
+ * Only renders children when the flag is enabled.
52
+ * Simpler alternative to Feature when you don't need fallback.
53
+ *
54
+ * @example
55
+ * ```tsx
56
+ * <FeatureEnabled flag="beta-features">
57
+ * <BetaBanner />
58
+ * </FeatureEnabled>
59
+ * ```
60
+ */
61
+ export declare function FeatureEnabled({ flag, children }: FeatureEnabledProps): import("react/jsx-runtime").JSX.Element | null;
62
+ /**
63
+ * FeatureDisabled Component Props
64
+ */
65
+ interface FeatureDisabledProps {
66
+ /** The feature flag key */
67
+ flag: string;
68
+ /** Content to render when the flag is disabled */
69
+ children: ReactNode;
70
+ }
71
+ /**
72
+ * FeatureDisabled Component
73
+ *
74
+ * Only renders children when the flag is disabled.
75
+ *
76
+ * @example
77
+ * ```tsx
78
+ * <FeatureDisabled flag="maintenance-mode">
79
+ * <MainContent />
80
+ * </FeatureDisabled>
81
+ * ```
82
+ */
83
+ export declare function FeatureDisabled({ flag, children }: FeatureDisabledProps): import("react/jsx-runtime").JSX.Element | null;
84
+ export {};
85
+ //# sourceMappingURL=components.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/react/components.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC;;GAEG;AACH,UAAU,YAAY;IACpB,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,QAAQ,EAAE,SAAS,CAAC;IACpB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,iDAAiD;IACjD,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,OAAO,CAAC,EACtB,IAAI,EACJ,QAAQ,EACR,QAAe,EACf,OAAc,GACf,EAAE,YAAY,2CAQd;AAED;;GAEG;AACH,UAAU,mBAAmB;IAC3B,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,mBAAmB,kDAQrE;AAED;;GAEG;AACH,UAAU,oBAAoB;IAC5B,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,oBAAoB,kDAQvE"}
@@ -0,0 +1,115 @@
1
+ import type { CustomerInfo, SignInOptions } from "../types";
2
+ /**
3
+ * Hook to get all feature flags
4
+ *
5
+ * @example
6
+ * ```tsx
7
+ * function MyComponent() {
8
+ * const { flags, isLoading, error } = useFlags();
9
+ *
10
+ * if (isLoading) return <div>Loading...</div>;
11
+ * if (error) return <div>Error: {error.message}</div>;
12
+ *
13
+ * return (
14
+ * <div>
15
+ * {flags['new-feature'] && <NewFeature />}
16
+ * </div>
17
+ * );
18
+ * }
19
+ * ```
20
+ */
21
+ export declare function useFlags(): {
22
+ flags: import("..").FlagsResponse;
23
+ isLoading: boolean;
24
+ error: Error | null;
25
+ refreshFlags: () => Promise<void>;
26
+ };
27
+ /**
28
+ * Hook to get a single feature flag
29
+ *
30
+ * @param key - The flag key
31
+ * @param defaultValue - Default value if flag is not found
32
+ *
33
+ * @example
34
+ * ```tsx
35
+ * function MyComponent() {
36
+ * const { enabled, isLoading } = useFlag('new-feature', false);
37
+ *
38
+ * if (isLoading) return <div>Loading...</div>;
39
+ *
40
+ * return enabled ? <NewFeature /> : <OldFeature />;
41
+ * }
42
+ * ```
43
+ */
44
+ export declare function useFlag(key: string, defaultValue?: boolean): {
45
+ enabled: boolean;
46
+ isLoading: boolean;
47
+ error: Error | null;
48
+ };
49
+ /**
50
+ * Hook to get a configuration by slug
51
+ *
52
+ * @param slug - The config slug
53
+ *
54
+ * @example
55
+ * ```tsx
56
+ * interface PricingConfig {
57
+ * plans: Array<{ name: string; price: number }>;
58
+ * }
59
+ *
60
+ * function PricingPage() {
61
+ * const { config, isLoading, error, refresh } = useConfig<PricingConfig>('pricing');
62
+ *
63
+ * if (isLoading) return <div>Loading...</div>;
64
+ * if (error) return <div>Error: {error.message}</div>;
65
+ *
66
+ * return (
67
+ * <div>
68
+ * {config?.plans.map(plan => (
69
+ * <div key={plan.name}>{plan.name}: ${plan.price}</div>
70
+ * ))}
71
+ * </div>
72
+ * );
73
+ * }
74
+ * ```
75
+ */
76
+ export declare function useConfig<T = Record<string, unknown>>(slug: string): {
77
+ config: T | null;
78
+ isLoading: boolean;
79
+ error: Error | null;
80
+ refresh: () => Promise<void>;
81
+ };
82
+ /**
83
+ * Hook to manage customer identification
84
+ *
85
+ * @example
86
+ * ```tsx
87
+ * function UserProfile() {
88
+ * const { customer, signIn, signOut } = useCustomer();
89
+ *
90
+ * useEffect(() => {
91
+ * // Sign in when user is authenticated
92
+ * signIn({ externalId: 'user-123', metadata: { plan: 'pro' } });
93
+ * }, []);
94
+ *
95
+ * return (
96
+ * <div>
97
+ * {customer ? (
98
+ * <>
99
+ * <p>Signed in as: {customer.externalId}</p>
100
+ * <button onClick={signOut}>Sign Out</button>
101
+ * </>
102
+ * ) : (
103
+ * <p>Not signed in</p>
104
+ * )}
105
+ * </div>
106
+ * );
107
+ * }
108
+ * ```
109
+ */
110
+ export declare function useCustomer(): {
111
+ customer: CustomerInfo | null;
112
+ signIn: (options: SignInOptions) => Promise<CustomerInfo>;
113
+ signOut: () => void;
114
+ };
115
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/react/hooks.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAkB,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE5E;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,QAAQ;;;;;EAGvB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,GAAE,OAAe;;;;EAKjE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM;;;;;EA0ClE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,WAAW,IAUpB;IACH,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAC1D,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CACF"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * ShipOS SDK React Integration
3
+ *
4
+ * React hooks and components for ShipOS feature flags, configs, and customer identification.
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * import { ShipOSProvider, useFlag, useCustomer, Feature } from '@shipos/sdk/react';
9
+ *
10
+ * function App() {
11
+ * return (
12
+ * <ShipOSProvider config={{ apiKey: 'your-api-key' }}>
13
+ * <Feature flag="new-feature">
14
+ * <NewFeature />
15
+ * </Feature>
16
+ * </ShipOSProvider>
17
+ * );
18
+ * }
19
+ * ```
20
+ */
21
+ export { ShipOSProvider, useShipOS } from "./provider";
22
+ export { useFlags, useFlag, useConfig, useCustomer } from "./hooks";
23
+ export { Feature, FeatureEnabled, FeatureDisabled } from "./components";
24
+ export type { ShipOSConfig, FlagsResponse, ConfigResponse, CustomerInfo, SignInOptions, } from "../types";
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAGpE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGxE,YAAY,EACV,YAAY,EACZ,aAAa,EACb,cAAc,EACd,YAAY,EACZ,aAAa,GACd,MAAM,UAAU,CAAC"}
@@ -0,0 +1 @@
1
+ class P{store=new Map;defaultTTL;constructor(G=60000){this.defaultTTL=G}get(G){let q=this.store.get(G);if(!q)return null;if(Date.now()-q.timestamp>this.defaultTTL)return this.store.delete(G),null;return q.data}set(G,q){this.store.set(G,{data:q,timestamp:Date.now()})}delete(G){this.store.delete(G)}clear(){this.store.clear()}setTTL(G){this.defaultTTL=G}}class _{ctx;constructor(G){this.ctx=G}async getAll(){let G=`flags:${this.ctx.getEnvironment()}`,q=this.ctx.cache.get(G);if(q)return this.ctx.log("Returning cached flags"),q;let z=await this.ctx.request("/v1/flags");return this.ctx.cache.set(G,z),z}async get(G,q=!1){return(await this.getAll())[G]??q}async refresh(){let G=`flags:${this.ctx.getEnvironment()}`;return this.ctx.cache.delete(G),this.getAll()}}class I{ctx;constructor(G){this.ctx=G}async get(G){let q=`config:${this.ctx.getEnvironment()}:${G}`,z=this.ctx.cache.get(q);if(z)return this.ctx.log(`Returning cached config: ${G}`),z;let J=await this.ctx.request(`/v1/config/${G}`);return this.ctx.cache.set(q,J),J}async refresh(G){let q=`config:${this.ctx.getEnvironment()}:${G}`;return this.ctx.cache.delete(q),this.get(G)}}class j{ctx;customer=null;constructor(G){this.ctx=G}async signIn(G){if(!G.externalId)throw Error("ShipOS: externalId is required for signIn");return this.ctx.log(`Signing in customer: ${G.externalId}`),this.customer={externalId:G.externalId,metadata:G.metadata},this.ctx.setCustomerId(G.externalId),await this.ctx.request("/v1/customers/identify",{method:"POST",body:{externalId:G.externalId,metadata:G.metadata??{}}}),this.ctx.log(`Customer signed in: ${G.externalId}`),this.customer}signOut(){this.ctx.log("Signing out customer"),this.customer=null,this.ctx.setCustomerId(null)}get(){return this.customer}}var C="https://api.shipos.app",k=60000,x="0.1.0";class w{apiKey;baseUrl;environment;cache;debug;customerId=null;featureFlags;configs;customers;constructor(G){if(!G.apiKey)throw Error("ShipOS: apiKey is required");this.apiKey=G.apiKey,this.baseUrl=G.baseUrl||C,this.environment=G.environment||"production",this.cache=new P(G.cacheTTL||k),this.debug=G.debug||!1;let q={request:this.request.bind(this),cache:this.cache,getEnvironment:this.getEnvironment.bind(this),log:this.log.bind(this),setCustomerId:(z)=>{this.customerId=z}};this.featureFlags=new _(q),this.configs=new I(q),this.customers=new j(q)}log(...G){if(this.debug)console.log("[ShipOS]",...G)}async request(G,q={}){let z=`${this.baseUrl}${G}`,J=q.method||"GET";this.log(`${J} ${z}`);let Y={"x-shipos-key":this.apiKey,"x-shipos-env":this.environment,"x-shipos-sdk-version":x,"Content-Type":"application/json"};if(this.customerId)Y["x-shipos-customer-id"]=this.customerId;let Q={method:J,headers:Y};if(q.body&&J!=="GET")Q.body=JSON.stringify(q.body);let Z=await fetch(z,Q);if(!Z.ok){let B=await Z.json().catch(()=>({error:`HTTP ${Z.status}`,code:"HTTP_ERROR"}));throw Error(B.error||`Request failed: ${Z.status}`)}return Z.json()}clearCache(){this.cache.clear(),this.log("Cache cleared")}setEnvironment(G){this.environment=G,this.cache.clear(),this.log(`Environment changed to: ${G}`)}getEnvironment(){return this.environment}}function F(G){return new w(G)}import{createContext as m,useContext as p,useState as H,useEffect as h,useCallback as U}from"react";import{jsxDEV as d}from"react/jsx-dev-runtime";var T=m(null);function f({config:G,children:q,initialFlags:z={}}){let[J]=H(()=>new w(G)),[Y,Q]=H(z),[Z,B]=H(Object.keys(z).length===0),[M,N]=H(null),[W,O]=H(null),D=U(async()=>{try{B(!0),N(null);let X=await J.featureFlags.getAll();Q(X)}catch(X){N(X instanceof Error?X:Error("Failed to fetch flags"))}finally{B(!1)}},[J]),L=U(async()=>{try{N(null);let X=await J.featureFlags.refresh();Q(X)}catch(X){N(X instanceof Error?X:Error("Failed to refresh flags"))}},[J]),E=U(async(X)=>{let V=await J.customers.signIn(X);return O(V),V},[J]),y=U(()=>{J.customers.signOut(),O(null)},[J]);h(()=>{if(Object.keys(z).length===0)D()},[D,z]);let S={client:J,flags:Y,isLoading:Z,error:M,refreshFlags:L,customer:W,signIn:E,signOut:y};return d(T.Provider,{value:S,children:q},void 0,!1,void 0,this)}function $(){let G=p(T);if(!G)throw Error("useShipOS must be used within a ShipOSProvider");return G}import{useState as v,useEffect as u,useCallback as b}from"react";function g(){let{flags:G,isLoading:q,error:z,refreshFlags:J}=$();return{flags:G,isLoading:q,error:z,refreshFlags:J}}function R(G,q=!1){let{flags:z,isLoading:J,error:Y}=$();return{enabled:z[G]??q,isLoading:J,error:Y}}function c(G){let{client:q}=$(),[z,J]=v(null),[Y,Q]=v(!0),[Z,B]=v(null),M=b(async()=>{try{Q(!0),B(null);let W=await q.configs.get(G);J(W)}catch(W){B(W instanceof Error?W:Error(`Failed to fetch config: ${G}`))}finally{Q(!1)}},[q,G]),N=b(async()=>{try{B(null);let W=await q.configs.refresh(G);J(W)}catch(W){B(W instanceof Error?W:Error(`Failed to refresh config: ${G}`))}},[q,G]);return u(()=>{M()},[M]),{config:z,isLoading:Y,error:Z,refresh:N}}function a(){let{customer:G,signIn:q,signOut:z}=$();return{customer:G,signIn:q,signOut:z}}import{jsxDEV as K,Fragment as A}from"react/jsx-dev-runtime";function l({flag:G,children:q,fallback:z=null,loading:J=null}){let{enabled:Y,isLoading:Q}=R(G);if(Q&&J)return K(A,{children:J},void 0,!1,void 0,this);return Y?K(A,{children:q},void 0,!1,void 0,this):K(A,{children:z},void 0,!1,void 0,this)}function r({flag:G,children:q}){let{enabled:z,isLoading:J}=R(G);if(J||!z)return null;return K(A,{children:q},void 0,!1,void 0,this)}function i({flag:G,children:q}){let{enabled:z,isLoading:J}=R(G);if(J||z)return null;return K(A,{children:q},void 0,!1,void 0,this)}export{$ as useShipOS,g as useFlags,R as useFlag,a as useCustomer,c as useConfig,f as ShipOSProvider,r as FeatureEnabled,i as FeatureDisabled,l as Feature};
@@ -0,0 +1,61 @@
1
+ import { type ReactNode } from "react";
2
+ import { ShipOS, type ShipOSConfig, type FlagsResponse, type CustomerInfo, type SignInOptions } from "../index";
3
+ /**
4
+ * ShipOS Context Value
5
+ */
6
+ interface ShipOSContextValue {
7
+ /** The ShipOS client instance */
8
+ client: ShipOS;
9
+ /** All feature flags (cached) */
10
+ flags: FlagsResponse;
11
+ /** Whether flags are currently loading */
12
+ isLoading: boolean;
13
+ /** Error if flags failed to load */
14
+ error: Error | null;
15
+ /** Refresh flags from the API */
16
+ refreshFlags: () => Promise<void>;
17
+ /** Current signed-in customer */
18
+ customer: CustomerInfo | null;
19
+ /** Sign in a customer */
20
+ signIn: (options: SignInOptions) => Promise<CustomerInfo>;
21
+ /** Sign out the current customer */
22
+ signOut: () => void;
23
+ }
24
+ /**
25
+ * ShipOS Provider Props
26
+ */
27
+ interface ShipOSProviderProps {
28
+ /** ShipOS configuration */
29
+ config: ShipOSConfig;
30
+ /** Child components */
31
+ children: ReactNode;
32
+ /** Initial flags (for SSR) */
33
+ initialFlags?: FlagsResponse;
34
+ }
35
+ /**
36
+ * ShipOS Provider
37
+ *
38
+ * Provides the ShipOS client, flags, and customer context to all child components.
39
+ *
40
+ * @example
41
+ * ```tsx
42
+ * import { ShipOSProvider } from '@shipos/sdk/react';
43
+ *
44
+ * function App() {
45
+ * return (
46
+ * <ShipOSProvider config={{ apiKey: 'your-api-key' }}>
47
+ * <YourApp />
48
+ * </ShipOSProvider>
49
+ * );
50
+ * }
51
+ * ```
52
+ */
53
+ export declare function ShipOSProvider({ config, children, initialFlags, }: ShipOSProviderProps): import("react/jsx-runtime").JSX.Element;
54
+ /**
55
+ * Hook to access the ShipOS context
56
+ *
57
+ * @throws Error if used outside of ShipOSProvider
58
+ */
59
+ export declare function useShipOS(): ShipOSContextValue;
60
+ export {};
61
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/react/provider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EACL,MAAM,EACN,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,aAAa,EACnB,MAAM,UAAU,CAAC;AAElB;;GAEG;AACH,UAAU,kBAAkB;IAC1B,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,KAAK,EAAE,aAAa,CAAC;IACrB,0CAA0C;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,oCAAoC;IACpC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,iCAAiC;IACjC,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,iCAAiC;IACjC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAC9B,yBAAyB;IACzB,MAAM,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAC1D,oCAAoC;IACpC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAID;;GAEG;AACH,UAAU,mBAAmB;IAC3B,2BAA2B;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,uBAAuB;IACvB,QAAQ,EAAE,SAAS,CAAC;IACpB,8BAA8B;IAC9B,YAAY,CAAC,EAAE,aAAa,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,QAAQ,EACR,YAAiB,GAClB,EAAE,mBAAmB,2CAqErB;AAED;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,kBAAkB,CAM9C"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * ShipOS SDK Types
3
+ */
4
+ /**
5
+ * Configuration options for the ShipOS client
6
+ */
7
+ export interface ShipOSConfig {
8
+ /** Your ShipOS API key */
9
+ apiKey: string;
10
+ /** Base URL for the ShipOS API (defaults to production) */
11
+ baseUrl?: string;
12
+ /** Environment to fetch flags/configs for (defaults to 'production') */
13
+ environment?: string;
14
+ /** Cache TTL in milliseconds (defaults to 60000 - 1 minute) */
15
+ cacheTTL?: number;
16
+ /** Enable debug logging */
17
+ debug?: boolean;
18
+ }
19
+ /**
20
+ * Feature flags response type
21
+ */
22
+ export type FlagsResponse = Record<string, boolean>;
23
+ /**
24
+ * Config response type (generic for typed configs)
25
+ */
26
+ export type ConfigResponse<T = Record<string, unknown>> = T;
27
+ /**
28
+ * API error response
29
+ */
30
+ export interface ApiError {
31
+ error: string;
32
+ code?: string;
33
+ }
34
+ /**
35
+ * Cache entry with timestamp
36
+ */
37
+ export interface CacheEntry<T> {
38
+ data: T;
39
+ timestamp: number;
40
+ }
41
+ /**
42
+ * Result type for async operations
43
+ */
44
+ export type Result<T, E = Error> = {
45
+ success: true;
46
+ data: T;
47
+ } | {
48
+ success: false;
49
+ error: E;
50
+ };
51
+ /**
52
+ * Customer information returned after sign-in
53
+ */
54
+ export interface CustomerInfo {
55
+ /** External ID used to identify the customer */
56
+ externalId: string;
57
+ /** Optional metadata associated with the customer */
58
+ metadata?: Record<string, unknown>;
59
+ }
60
+ /**
61
+ * Options for signing in a customer
62
+ */
63
+ export interface SignInOptions {
64
+ /** External ID used to identify the customer in your system */
65
+ externalId: string;
66
+ /** Optional JSON metadata to associate with the customer */
67
+ metadata?: Record<string, unknown>;
68
+ }
69
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEpD;;GAEG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,IAAI,EAAE,CAAC,CAAC;IACR,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,MAAM,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK,IAC3B;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GAC1B;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC;AAEjC;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC"}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "shipos",
3
+ "version": "0.0.0",
4
+ "description": "ShipOS SDK for feature flags and global configs",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ },
14
+ "./react": {
15
+ "import": "./dist/react/index.js",
16
+ "types": "./dist/react/index.d.ts"
17
+ }
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "README.md"
22
+ ],
23
+ "scripts": {
24
+ "build:bundle": "bun build ./src/index.ts ./src/react/index.ts --outdir ./dist --target browser --format esm --external react",
25
+ "build": "bun run build:bundle -- --minify && bun run build:types",
26
+ "build:types": "tsc --emitDeclarationOnly --declaration --outDir ./dist",
27
+ "dev": "bun run build:bundle -- --watch",
28
+ "clean": "rm -rf dist",
29
+ "prepublishOnly": "bun run build"
30
+ },
31
+ "keywords": [
32
+ "shipos",
33
+ "feature-flags",
34
+ "config",
35
+ "sdk",
36
+ "react"
37
+ ],
38
+ "author": "",
39
+ "license": "UNLICENSED",
40
+ "devDependencies": {
41
+ "@types/bun": "latest",
42
+ "@types/react": "^19.0.0"
43
+ },
44
+ "peerDependencies": {
45
+ "react": "^18 || ^19",
46
+ "typescript": "^5"
47
+ },
48
+ "peerDependenciesMeta": {
49
+ "react": {
50
+ "optional": true
51
+ }
52
+ }
53
+ }