shipos 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 +225 -0
- package/dist/cache.d.ts +29 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/client.d.ts +53 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +214 -0
- package/dist/modules/configs.d.ts +56 -0
- package/dist/modules/configs.d.ts.map +1 -0
- package/dist/modules/customers.d.ts +76 -0
- package/dist/modules/customers.d.ts.map +1 -0
- package/dist/modules/feature-flags.d.ts +66 -0
- package/dist/modules/feature-flags.d.ts.map +1 -0
- package/dist/react/components.d.ts +85 -0
- package/dist/react/components.d.ts.map +1 -0
- package/dist/react/hooks.d.ts +115 -0
- package/dist/react/hooks.d.ts.map +1 -0
- package/dist/react/index.d.ts +25 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +388 -0
- package/dist/react/provider.d.ts +61 -0
- package/dist/react/provider.d.ts.map +1 -0
- package/dist/types.d.ts +69 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +52 -0
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
|
package/dist/cache.d.ts
ADDED
|
@@ -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"}
|
package/dist/client.d.ts
ADDED
|
@@ -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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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,214 @@
|
|
|
1
|
+
// src/cache.ts
|
|
2
|
+
class Cache {
|
|
3
|
+
store = new Map;
|
|
4
|
+
defaultTTL;
|
|
5
|
+
constructor(defaultTTL = 60000) {
|
|
6
|
+
this.defaultTTL = defaultTTL;
|
|
7
|
+
}
|
|
8
|
+
get(key) {
|
|
9
|
+
const entry = this.store.get(key);
|
|
10
|
+
if (!entry) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
if (Date.now() - entry.timestamp > this.defaultTTL) {
|
|
14
|
+
this.store.delete(key);
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
return entry.data;
|
|
18
|
+
}
|
|
19
|
+
set(key, data) {
|
|
20
|
+
this.store.set(key, {
|
|
21
|
+
data,
|
|
22
|
+
timestamp: Date.now()
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
delete(key) {
|
|
26
|
+
this.store.delete(key);
|
|
27
|
+
}
|
|
28
|
+
clear() {
|
|
29
|
+
this.store.clear();
|
|
30
|
+
}
|
|
31
|
+
setTTL(ttl) {
|
|
32
|
+
this.defaultTTL = ttl;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/modules/feature-flags.ts
|
|
37
|
+
class FeatureFlagsModule {
|
|
38
|
+
ctx;
|
|
39
|
+
constructor(ctx) {
|
|
40
|
+
this.ctx = ctx;
|
|
41
|
+
}
|
|
42
|
+
async getAll() {
|
|
43
|
+
const cacheKey = `flags:${this.ctx.getEnvironment()}`;
|
|
44
|
+
const cached = this.ctx.cache.get(cacheKey);
|
|
45
|
+
if (cached) {
|
|
46
|
+
this.ctx.log("Returning cached flags");
|
|
47
|
+
return cached;
|
|
48
|
+
}
|
|
49
|
+
const flags = await this.ctx.request("/v1/flags");
|
|
50
|
+
this.ctx.cache.set(cacheKey, flags);
|
|
51
|
+
return flags;
|
|
52
|
+
}
|
|
53
|
+
async get(key, defaultValue = false) {
|
|
54
|
+
const flags = await this.getAll();
|
|
55
|
+
return flags[key] ?? defaultValue;
|
|
56
|
+
}
|
|
57
|
+
async refresh() {
|
|
58
|
+
const cacheKey = `flags:${this.ctx.getEnvironment()}`;
|
|
59
|
+
this.ctx.cache.delete(cacheKey);
|
|
60
|
+
return this.getAll();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// src/modules/configs.ts
|
|
65
|
+
class ConfigsModule {
|
|
66
|
+
ctx;
|
|
67
|
+
constructor(ctx) {
|
|
68
|
+
this.ctx = ctx;
|
|
69
|
+
}
|
|
70
|
+
async get(slug) {
|
|
71
|
+
const cacheKey = `config:${this.ctx.getEnvironment()}:${slug}`;
|
|
72
|
+
const cached = this.ctx.cache.get(cacheKey);
|
|
73
|
+
if (cached) {
|
|
74
|
+
this.ctx.log(`Returning cached config: ${slug}`);
|
|
75
|
+
return cached;
|
|
76
|
+
}
|
|
77
|
+
const config = await this.ctx.request(`/v1/config/${slug}`);
|
|
78
|
+
this.ctx.cache.set(cacheKey, config);
|
|
79
|
+
return config;
|
|
80
|
+
}
|
|
81
|
+
async refresh(slug) {
|
|
82
|
+
const cacheKey = `config:${this.ctx.getEnvironment()}:${slug}`;
|
|
83
|
+
this.ctx.cache.delete(cacheKey);
|
|
84
|
+
return this.get(slug);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/modules/customers.ts
|
|
89
|
+
class CustomersModule {
|
|
90
|
+
ctx;
|
|
91
|
+
customer = null;
|
|
92
|
+
constructor(ctx) {
|
|
93
|
+
this.ctx = ctx;
|
|
94
|
+
}
|
|
95
|
+
async signIn(options) {
|
|
96
|
+
if (!options.externalId) {
|
|
97
|
+
throw new Error("ShipOS: externalId is required for signIn");
|
|
98
|
+
}
|
|
99
|
+
this.ctx.log(`Signing in customer: ${options.externalId}`);
|
|
100
|
+
this.customer = {
|
|
101
|
+
externalId: options.externalId,
|
|
102
|
+
metadata: options.metadata
|
|
103
|
+
};
|
|
104
|
+
this.ctx.setCustomerId(options.externalId);
|
|
105
|
+
await this.ctx.request("/v1/customers/identify", {
|
|
106
|
+
method: "POST",
|
|
107
|
+
body: {
|
|
108
|
+
externalId: options.externalId,
|
|
109
|
+
metadata: options.metadata ?? {}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
this.ctx.log(`Customer signed in: ${options.externalId}`);
|
|
113
|
+
return this.customer;
|
|
114
|
+
}
|
|
115
|
+
signOut() {
|
|
116
|
+
this.ctx.log("Signing out customer");
|
|
117
|
+
this.customer = null;
|
|
118
|
+
this.ctx.setCustomerId(null);
|
|
119
|
+
}
|
|
120
|
+
get() {
|
|
121
|
+
return this.customer;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/client.ts
|
|
126
|
+
var DEFAULT_BASE_URL = "https://api.shipos.app";
|
|
127
|
+
var DEFAULT_CACHE_TTL = 60000;
|
|
128
|
+
var SDK_VERSION = "0.1.0";
|
|
129
|
+
|
|
130
|
+
class ShipOS {
|
|
131
|
+
apiKey;
|
|
132
|
+
baseUrl;
|
|
133
|
+
environment;
|
|
134
|
+
cache;
|
|
135
|
+
debug;
|
|
136
|
+
customerId = null;
|
|
137
|
+
featureFlags;
|
|
138
|
+
configs;
|
|
139
|
+
customers;
|
|
140
|
+
constructor(config) {
|
|
141
|
+
if (!config.apiKey) {
|
|
142
|
+
throw new Error("ShipOS: apiKey is required");
|
|
143
|
+
}
|
|
144
|
+
this.apiKey = config.apiKey;
|
|
145
|
+
this.baseUrl = config.baseUrl || DEFAULT_BASE_URL;
|
|
146
|
+
this.environment = config.environment || "production";
|
|
147
|
+
this.cache = new Cache(config.cacheTTL || DEFAULT_CACHE_TTL);
|
|
148
|
+
this.debug = config.debug || false;
|
|
149
|
+
const ctx = {
|
|
150
|
+
request: this.request.bind(this),
|
|
151
|
+
cache: this.cache,
|
|
152
|
+
getEnvironment: this.getEnvironment.bind(this),
|
|
153
|
+
log: this.log.bind(this),
|
|
154
|
+
setCustomerId: (id) => {
|
|
155
|
+
this.customerId = id;
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
this.featureFlags = new FeatureFlagsModule(ctx);
|
|
159
|
+
this.configs = new ConfigsModule(ctx);
|
|
160
|
+
this.customers = new CustomersModule(ctx);
|
|
161
|
+
}
|
|
162
|
+
log(...args) {
|
|
163
|
+
if (this.debug) {
|
|
164
|
+
console.log("[ShipOS]", ...args);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
async request(endpoint, options = {}) {
|
|
168
|
+
const url = `${this.baseUrl}${endpoint}`;
|
|
169
|
+
const method = options.method || "GET";
|
|
170
|
+
this.log(`${method} ${url}`);
|
|
171
|
+
const headers = {
|
|
172
|
+
"x-shipos-key": this.apiKey,
|
|
173
|
+
"x-shipos-env": this.environment,
|
|
174
|
+
"x-shipos-sdk-version": SDK_VERSION,
|
|
175
|
+
"Content-Type": "application/json"
|
|
176
|
+
};
|
|
177
|
+
if (this.customerId) {
|
|
178
|
+
headers["x-shipos-customer-id"] = this.customerId;
|
|
179
|
+
}
|
|
180
|
+
const fetchOptions = { method, headers };
|
|
181
|
+
if (options.body && method !== "GET") {
|
|
182
|
+
fetchOptions.body = JSON.stringify(options.body);
|
|
183
|
+
}
|
|
184
|
+
const response = await fetch(url, fetchOptions);
|
|
185
|
+
if (!response.ok) {
|
|
186
|
+
const error = await response.json().catch(() => ({
|
|
187
|
+
error: `HTTP ${response.status}`,
|
|
188
|
+
code: "HTTP_ERROR"
|
|
189
|
+
}));
|
|
190
|
+
throw new Error(error.error || `Request failed: ${response.status}`);
|
|
191
|
+
}
|
|
192
|
+
return response.json();
|
|
193
|
+
}
|
|
194
|
+
clearCache() {
|
|
195
|
+
this.cache.clear();
|
|
196
|
+
this.log("Cache cleared");
|
|
197
|
+
}
|
|
198
|
+
setEnvironment(environment) {
|
|
199
|
+
this.environment = environment;
|
|
200
|
+
this.cache.clear();
|
|
201
|
+
this.log(`Environment changed to: ${environment}`);
|
|
202
|
+
}
|
|
203
|
+
getEnvironment() {
|
|
204
|
+
return this.environment;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function createShipOS(config) {
|
|
208
|
+
return new ShipOS(config);
|
|
209
|
+
}
|
|
210
|
+
export {
|
|
211
|
+
createShipOS,
|
|
212
|
+
ShipOS,
|
|
213
|
+
Cache
|
|
214
|
+
};
|
|
@@ -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"}
|