roboto-js 1.9.5 → 1.9.7
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/.last-build +1 -1
- package/README.md +580 -0
- package/dist/cjs/cookie_storage_adaptor.cjs +22 -7
- package/dist/cjs/index.cjs +137 -82
- package/dist/cjs/rbt_api.cjs +529 -298
- package/dist/cjs/version.cjs +2 -2
- package/dist/cookie_storage_adaptor.js +12 -26
- package/dist/esm/cookie_storage_adaptor.js +22 -7
- package/dist/esm/index.js +137 -82
- package/dist/esm/rbt_api.js +529 -298
- package/dist/esm/version.js +2 -2
- package/dist/index.js +118 -3
- package/dist/version.js +2 -2
- package/package.json +1 -1
- package/src/cookie_storage_adaptor.js +14 -15
- package/src/index.js +16 -0
- package/src/rbt_api.js +164 -0
- package/src/version.js +2 -2
package/.last-build
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2025-12-
|
|
1
|
+
2025-12-31T10:58:16.804Z
|
package/README.md
ADDED
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
# roboto-js
|
|
2
|
+
|
|
3
|
+
JavaScript/TypeScript SDK for the Roboto platform - a unified client library for managing objects, files, users, and real-time data synchronization.
|
|
4
|
+
|
|
5
|
+
**Version:** 1.9.5
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Object Management**: Create, read, update, and delete platform objects with a simple API
|
|
10
|
+
- **File Handling**: Upload and manage files with resumable uploads via tus protocol
|
|
11
|
+
- **User Authentication**: Login, registration, OAuth, and session management
|
|
12
|
+
- **Real-time Sync**: WebSocket-based live updates for collaborative applications
|
|
13
|
+
- **Access Control**: Fine-grained permissions with user, group, and organization-level sharing
|
|
14
|
+
- **Storage Adapters**: Flexible authentication storage (cookies, localStorage, custom)
|
|
15
|
+
- **Metrics & Analytics**: Built-in metrics API for tracking and analytics
|
|
16
|
+
- **Dual Module Support**: Works in both CommonJS and ES Module environments
|
|
17
|
+
- **Browser & Node.js**: Runs in browsers and Node.js server environments
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install roboto-js
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
### Basic Initialization
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
import Roboto from 'roboto-js';
|
|
31
|
+
|
|
32
|
+
const roboto = new Roboto({
|
|
33
|
+
host: 'your-api-host.com',
|
|
34
|
+
accessKey: 'your-access-key'
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Authentication
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
// Login
|
|
42
|
+
const user = await roboto.login({
|
|
43
|
+
email: 'user@example.com',
|
|
44
|
+
password: 'password'
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Get current user
|
|
48
|
+
const currentUser = await roboto.loadCurrentUser();
|
|
49
|
+
|
|
50
|
+
// Logout
|
|
51
|
+
await roboto.logout();
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Working with Objects
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
// Create a new object
|
|
58
|
+
const site = await roboto.create('<@doc_website.site>', {
|
|
59
|
+
configs: {
|
|
60
|
+
label: 'My Website',
|
|
61
|
+
domain: 'example.com'
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Load an object
|
|
66
|
+
const loadedSite = await roboto.load('<@doc_website.site>', 'site-id-123');
|
|
67
|
+
|
|
68
|
+
// Update and save
|
|
69
|
+
site.set('configs.label', 'Updated Website');
|
|
70
|
+
await site.save();
|
|
71
|
+
|
|
72
|
+
// Query objects
|
|
73
|
+
const sites = await roboto.query('<@doc_website.site>', {
|
|
74
|
+
where: 'configs.status=active'
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### File Uploads
|
|
79
|
+
|
|
80
|
+
```javascript
|
|
81
|
+
// Create a file object
|
|
82
|
+
const file = await roboto.createFile({
|
|
83
|
+
filename: 'document.pdf',
|
|
84
|
+
mimetype: 'application/pdf'
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Upload with progress tracking
|
|
88
|
+
await file.upload(fileBlob, {
|
|
89
|
+
onProgress: (bytesUploaded, bytesTotal) => {
|
|
90
|
+
const percent = (bytesUploaded / bytesTotal) * 100;
|
|
91
|
+
console.log(`Upload progress: ${percent.toFixed(2)}%`);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Configuration Options
|
|
97
|
+
|
|
98
|
+
```javascript
|
|
99
|
+
const roboto = new Roboto({
|
|
100
|
+
host: 'api.example.com', // API host (required)
|
|
101
|
+
accessKey: 'your-access-key', // Access key (required)
|
|
102
|
+
authToken: 'token', // Optional: pre-set auth token
|
|
103
|
+
apiKey: 'key', // Optional: API key for service calls
|
|
104
|
+
useCookies: true, // Use cookies for auth (default: true)
|
|
105
|
+
cookieDomain: 'auto', // Cookie domain: 'auto', 'none', or explicit domain
|
|
106
|
+
localStorageAdaptor: customAdaptor, // Custom storage adapter
|
|
107
|
+
disableWebSocket: false, // Disable WebSocket connections
|
|
108
|
+
metricsHost: 'metrics.example.com' // Separate metrics host (optional)
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Core API Methods
|
|
113
|
+
|
|
114
|
+
### Object Operations
|
|
115
|
+
|
|
116
|
+
- `create(type, data)` - Create a new object
|
|
117
|
+
- `load(type, ids, options)` - Load object(s) by ID
|
|
118
|
+
- `query(type, params)` - Query objects with filters
|
|
119
|
+
- `wrapAsRbtObjects(data)` - Convert raw JSON to RbtObject instances
|
|
120
|
+
|
|
121
|
+
### User Management
|
|
122
|
+
|
|
123
|
+
- `login(params)` - Authenticate user
|
|
124
|
+
- `loginWithOauth(params)` - OAuth authentication
|
|
125
|
+
- `logout()` - End session
|
|
126
|
+
- `registerUser(params)` - Create new user account
|
|
127
|
+
- `loadCurrentUser()` - Get authenticated user
|
|
128
|
+
- `confirmUserEmail(params)` - Verify email address
|
|
129
|
+
|
|
130
|
+
### Organization Management
|
|
131
|
+
|
|
132
|
+
- `loadCurrentOrganization(forceReload)` - Load user's current organization
|
|
133
|
+
- `switchOrganization(orgId)` - Switch to a different organization
|
|
134
|
+
- `getCurrentOrganization()` - Get cached current organization
|
|
135
|
+
- `currentOrganization` - Getter for current organization
|
|
136
|
+
|
|
137
|
+
### File Operations
|
|
138
|
+
|
|
139
|
+
- `createFile(data)` - Create file object
|
|
140
|
+
- `loadFile(id)` - Load file by ID
|
|
141
|
+
- `loadFiles(ids)` - Load multiple files
|
|
142
|
+
|
|
143
|
+
### Task Execution
|
|
144
|
+
|
|
145
|
+
- `runTask(params, callbacks)` - Execute background task
|
|
146
|
+
- `stopJob(params)` - Cancel running job
|
|
147
|
+
- `pollTaskProgress(params)` - Check task status
|
|
148
|
+
|
|
149
|
+
### HTTP Methods
|
|
150
|
+
|
|
151
|
+
- `get(endpoint, params)` - GET request with auto-wrapping
|
|
152
|
+
- `post(endpoint, data)` - POST request with auto-wrapping
|
|
153
|
+
|
|
154
|
+
## RbtObject Methods
|
|
155
|
+
|
|
156
|
+
RbtObject is the core class for working with platform data:
|
|
157
|
+
|
|
158
|
+
```javascript
|
|
159
|
+
// Data access
|
|
160
|
+
object.get('path.to.property') // Get value
|
|
161
|
+
object.getData(['key1', 'key2']) // Get multiple values
|
|
162
|
+
object.set('path.to.property', value) // Set value
|
|
163
|
+
object.set('path', value, { merge: true }) // Merge objects
|
|
164
|
+
|
|
165
|
+
// Persistence
|
|
166
|
+
await object.save() // Save changes
|
|
167
|
+
await object.delete() // Delete object
|
|
168
|
+
await object.reload() // Refresh from server
|
|
169
|
+
|
|
170
|
+
// Metadata
|
|
171
|
+
object.id // Object ID
|
|
172
|
+
object.getType() // Object type
|
|
173
|
+
object.getRevision() // Revision number
|
|
174
|
+
object.hasUnsavedChanges() // Check for pending changes
|
|
175
|
+
|
|
176
|
+
// Real-time sync
|
|
177
|
+
object.enableRealtime() // Enable live updates
|
|
178
|
+
object.disableRealtime() // Disable live updates
|
|
179
|
+
object.on('change', callback) // Listen for changes
|
|
180
|
+
object.broadcastChange('path') // Broadcast to other clients
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Access Control & Sharing
|
|
184
|
+
|
|
185
|
+
Control who can access your objects:
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
// Make object public
|
|
189
|
+
await object.publishObject();
|
|
190
|
+
await object.unpublishObject();
|
|
191
|
+
|
|
192
|
+
// Check if published
|
|
193
|
+
if (object.isPublished()) {
|
|
194
|
+
console.log('Object is public');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Grant access to users
|
|
198
|
+
await object.grantAccess({
|
|
199
|
+
userIds: ['user1', 'user2'],
|
|
200
|
+
write: false // read-only
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// Grant access to groups
|
|
204
|
+
await object.grantAccess({
|
|
205
|
+
groupIds: ['grpAdmins'],
|
|
206
|
+
write: true // read and write
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Revoke access
|
|
210
|
+
await object.revokeAccess({
|
|
211
|
+
userIds: ['user1'],
|
|
212
|
+
groupIds: ['grpViewers']
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// Get current permissions
|
|
216
|
+
const perms = object.getSharing();
|
|
217
|
+
console.log(perms.readGrants.users);
|
|
218
|
+
console.log(perms.writeGrants.userGroups);
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
See [SHARING_GUIDE.md](./SHARING_GUIDE.md) for detailed examples and patterns.
|
|
222
|
+
|
|
223
|
+
## Organization Management
|
|
224
|
+
|
|
225
|
+
Manage the current organization context for multi-tenant applications:
|
|
226
|
+
|
|
227
|
+
```javascript
|
|
228
|
+
// Load current organization (automatic on login)
|
|
229
|
+
const org = await roboto.loadCurrentOrganization();
|
|
230
|
+
console.log('Current org:', org.get('name'));
|
|
231
|
+
|
|
232
|
+
// Access organization data
|
|
233
|
+
const orgName = org.get('name');
|
|
234
|
+
const taxId = org.get('profile.taxId');
|
|
235
|
+
|
|
236
|
+
// Access module-specific settings
|
|
237
|
+
const fiscalYearEnd = org.get('mod.accounting.fiscalYearEnd');
|
|
238
|
+
const defaultPipeline = org.get('mod.crm.defaultPipeline');
|
|
239
|
+
|
|
240
|
+
// Update organization data
|
|
241
|
+
org.set('name', 'Updated Company Name');
|
|
242
|
+
org.set('mod.accounting.baseCurrency', 'USD');
|
|
243
|
+
await org.save();
|
|
244
|
+
|
|
245
|
+
// Switch to a different organization
|
|
246
|
+
const newOrg = await roboto.switchOrganization('org-456');
|
|
247
|
+
console.log('Switched to:', newOrg.get('name'));
|
|
248
|
+
|
|
249
|
+
// Get cached organization (no API call)
|
|
250
|
+
const cached = roboto.getCurrentOrganization();
|
|
251
|
+
// or
|
|
252
|
+
const cached = roboto.currentOrganization;
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Organization on Login
|
|
256
|
+
|
|
257
|
+
Organizations are automatically loaded after successful login:
|
|
258
|
+
|
|
259
|
+
```javascript
|
|
260
|
+
await roboto.login({
|
|
261
|
+
email: 'user@example.com',
|
|
262
|
+
password: 'password'
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
// Organization is now available
|
|
266
|
+
const org = roboto.currentOrganization;
|
|
267
|
+
console.log('Logged in to:', org.get('name'));
|
|
268
|
+
|
|
269
|
+
// Disable automatic organization load
|
|
270
|
+
await roboto.login({
|
|
271
|
+
email: 'user@example.com',
|
|
272
|
+
password: 'password',
|
|
273
|
+
loadOrganization: false // Skip org loading
|
|
274
|
+
});
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Server-Side Organization Context
|
|
278
|
+
|
|
279
|
+
```javascript
|
|
280
|
+
// Express middleware with per-request organization
|
|
281
|
+
app.use((req, res, next) => {
|
|
282
|
+
req.roboto = new Roboto({
|
|
283
|
+
host: 'api.example.com',
|
|
284
|
+
accessKey: process.env.ROBOTO_ACCESS_KEY
|
|
285
|
+
}, req);
|
|
286
|
+
next();
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// Use in routes
|
|
290
|
+
app.get('/api/accounts', async (req, res) => {
|
|
291
|
+
const org = await req.roboto.loadCurrentOrganization();
|
|
292
|
+
|
|
293
|
+
// Query automatically scoped to organization via IAC
|
|
294
|
+
const accounts = await req.roboto.query('<@accounting.account>', {});
|
|
295
|
+
|
|
296
|
+
res.json({
|
|
297
|
+
organization: org.get('name'),
|
|
298
|
+
accounts
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Multi-Tenant Data Scoping
|
|
304
|
+
|
|
305
|
+
Organization context enables automatic multi-tenant data scoping:
|
|
306
|
+
|
|
307
|
+
```javascript
|
|
308
|
+
// All queries are automatically scoped to current organization
|
|
309
|
+
const org = await roboto.loadCurrentOrganization();
|
|
310
|
+
|
|
311
|
+
// These queries only return data the organization has access to
|
|
312
|
+
const accounts = await roboto.query('<@accounting.account>', {});
|
|
313
|
+
const invoices = await roboto.query('<@accounting.invoice>', {});
|
|
314
|
+
const contacts = await roboto.query('<@crm.contact>', {});
|
|
315
|
+
|
|
316
|
+
// Switch organizations and queries update automatically
|
|
317
|
+
await roboto.switchOrganization('different-org-id');
|
|
318
|
+
const newAccounts = await roboto.query('<@accounting.account>', {});
|
|
319
|
+
// Now returns accounts for the new organization
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## Real-time Collaboration
|
|
323
|
+
|
|
324
|
+
Enable live updates across clients:
|
|
325
|
+
|
|
326
|
+
```javascript
|
|
327
|
+
// Enable real-time on an object
|
|
328
|
+
const doc = await roboto.load('<@doc.document>', 'doc-123');
|
|
329
|
+
doc.enableRealtime();
|
|
330
|
+
|
|
331
|
+
// Listen for changes
|
|
332
|
+
doc.on('change', (path, value) => {
|
|
333
|
+
console.log(`${path} changed to`, value);
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
// Broadcast changes to other clients
|
|
337
|
+
doc.set('content.text', 'Updated text');
|
|
338
|
+
doc.broadcastChange('content.text'); // Others receive this immediately
|
|
339
|
+
|
|
340
|
+
// Disable when done
|
|
341
|
+
doc.disableRealtime();
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
## Storage Adapters
|
|
345
|
+
|
|
346
|
+
### Cookie Storage (Default for Browser)
|
|
347
|
+
|
|
348
|
+
```javascript
|
|
349
|
+
import Roboto, { CookieStorageAdaptor } from 'roboto-js';
|
|
350
|
+
|
|
351
|
+
const roboto = new Roboto({
|
|
352
|
+
host: 'api.example.com',
|
|
353
|
+
accessKey: 'key',
|
|
354
|
+
useCookies: true, // Enabled by default
|
|
355
|
+
cookieDomain: 'auto' // Auto-detect root domain
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// Custom cookie configuration
|
|
359
|
+
const cookieAdaptor = new CookieStorageAdaptor({
|
|
360
|
+
secure: true,
|
|
361
|
+
sameSite: 'Lax',
|
|
362
|
+
maxAge: 86400, // 24 hours
|
|
363
|
+
domain: '.example.com'
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
const roboto = new Roboto({
|
|
367
|
+
host: 'api.example.com',
|
|
368
|
+
accessKey: 'key',
|
|
369
|
+
localStorageAdaptor: cookieAdaptor
|
|
370
|
+
});
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### Custom Storage Adapter
|
|
374
|
+
|
|
375
|
+
```javascript
|
|
376
|
+
const customAdaptor = {
|
|
377
|
+
getItem: async (key) => {
|
|
378
|
+
// Return stored value
|
|
379
|
+
},
|
|
380
|
+
setItem: async (key, value) => {
|
|
381
|
+
// Store value
|
|
382
|
+
},
|
|
383
|
+
removeItem: async (key) => {
|
|
384
|
+
// Remove value
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
const roboto = new Roboto({
|
|
389
|
+
host: 'api.example.com',
|
|
390
|
+
accessKey: 'key',
|
|
391
|
+
localStorageAdaptor: customAdaptor
|
|
392
|
+
});
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
## Server-Side Usage (Node.js)
|
|
396
|
+
|
|
397
|
+
Use with Express middleware for per-request instances:
|
|
398
|
+
|
|
399
|
+
```javascript
|
|
400
|
+
import Roboto from 'roboto-js';
|
|
401
|
+
|
|
402
|
+
// Middleware to attach roboto to each request
|
|
403
|
+
app.use((req, res, next) => {
|
|
404
|
+
// proxyReq allows per-request authentication
|
|
405
|
+
req.roboto = new Roboto({
|
|
406
|
+
host: 'api.example.com',
|
|
407
|
+
accessKey: process.env.ROBOTO_ACCESS_KEY
|
|
408
|
+
}, req); // Pass request object
|
|
409
|
+
|
|
410
|
+
next();
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
// Use in routes
|
|
414
|
+
app.get('/api/sites', async (req, res) => {
|
|
415
|
+
const sites = await req.roboto.query('<@doc_website.site>', {});
|
|
416
|
+
res.json(sites);
|
|
417
|
+
});
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
## Metrics API
|
|
421
|
+
|
|
422
|
+
Track events and analytics:
|
|
423
|
+
|
|
424
|
+
```javascript
|
|
425
|
+
// Using default metrics endpoint
|
|
426
|
+
await roboto.metrics.logEvent({
|
|
427
|
+
event: 'user_action',
|
|
428
|
+
properties: {
|
|
429
|
+
action: 'button_click',
|
|
430
|
+
page: 'home'
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
// Custom metrics host
|
|
435
|
+
roboto.setMetricsHost('metrics.example.com');
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
## Environment-Specific Features
|
|
439
|
+
|
|
440
|
+
### Browser
|
|
441
|
+
|
|
442
|
+
- Automatic WebSocket connection
|
|
443
|
+
- IndexedDB for local caching
|
|
444
|
+
- Cookie-based authentication by default
|
|
445
|
+
- Cross-subdomain cookie support
|
|
446
|
+
|
|
447
|
+
### Node.js
|
|
448
|
+
|
|
449
|
+
- Per-request instances with `proxyReq`
|
|
450
|
+
- Custom header support for authentication
|
|
451
|
+
- No WebSocket auto-connection
|
|
452
|
+
|
|
453
|
+
## Advanced Features
|
|
454
|
+
|
|
455
|
+
### Auto-Wrapping Responses
|
|
456
|
+
|
|
457
|
+
The SDK automatically converts doctree objects to RbtObject instances:
|
|
458
|
+
|
|
459
|
+
```javascript
|
|
460
|
+
// Raw API call returns plain objects
|
|
461
|
+
const response = await fetch('/api/custom-endpoint');
|
|
462
|
+
const data = await response.json();
|
|
463
|
+
|
|
464
|
+
// Wrap for RbtObject functionality
|
|
465
|
+
const objects = roboto.wrapAsRbtObjects(data.items);
|
|
466
|
+
|
|
467
|
+
// Now use RbtObject methods
|
|
468
|
+
objects[0].set('title', 'New Title');
|
|
469
|
+
await objects[0].save();
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Object Caching
|
|
473
|
+
|
|
474
|
+
Objects are cached automatically to prevent duplicate instances:
|
|
475
|
+
|
|
476
|
+
```javascript
|
|
477
|
+
// Both calls return the same instance
|
|
478
|
+
const obj1 = await roboto.load('<@doc.item>', 'abc123');
|
|
479
|
+
const obj2 = await roboto.load('<@doc.item>', 'abc123');
|
|
480
|
+
|
|
481
|
+
console.log(obj1 === obj2); // true
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### Error Handling
|
|
485
|
+
|
|
486
|
+
Set a custom error handler:
|
|
487
|
+
|
|
488
|
+
```javascript
|
|
489
|
+
roboto.setErrorHandler((error, context) => {
|
|
490
|
+
console.error('API Error:', error.message);
|
|
491
|
+
console.error('Context:', context);
|
|
492
|
+
|
|
493
|
+
// Custom error reporting
|
|
494
|
+
errorReporter.report(error);
|
|
495
|
+
});
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
## Build & Development
|
|
499
|
+
|
|
500
|
+
```bash
|
|
501
|
+
# Install dependencies
|
|
502
|
+
npm install
|
|
503
|
+
|
|
504
|
+
# Build for production (strips console.log, keeps console.error)
|
|
505
|
+
npm run build
|
|
506
|
+
|
|
507
|
+
# Build CommonJS only
|
|
508
|
+
npm run build:cjs
|
|
509
|
+
|
|
510
|
+
# Build ES Modules only
|
|
511
|
+
npm run build:esm
|
|
512
|
+
|
|
513
|
+
# Update version
|
|
514
|
+
npm run update-version
|
|
515
|
+
|
|
516
|
+
# Clean install
|
|
517
|
+
npm run clean
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
See [BUILD_NOTES.md](./BUILD_NOTES.md) for build configuration details.
|
|
521
|
+
|
|
522
|
+
## Module Formats
|
|
523
|
+
|
|
524
|
+
The package supports both module systems:
|
|
525
|
+
|
|
526
|
+
**ES Modules (import)**
|
|
527
|
+
```javascript
|
|
528
|
+
import Roboto, { RbtObject, RbtFile } from 'roboto-js';
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
**CommonJS (require)**
|
|
532
|
+
```javascript
|
|
533
|
+
const Roboto = require('roboto-js');
|
|
534
|
+
const { RbtObject, RbtFile } = require('roboto-js');
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
## TypeScript Support
|
|
538
|
+
|
|
539
|
+
While this is a JavaScript library, it works seamlessly with TypeScript projects. Type definitions may be added in future versions.
|
|
540
|
+
|
|
541
|
+
## Examples
|
|
542
|
+
|
|
543
|
+
See the [examples](./examples) directory for complete working examples:
|
|
544
|
+
|
|
545
|
+
- [sharing-example.js](./examples/sharing-example.js) - Access control patterns
|
|
546
|
+
|
|
547
|
+
## Exports
|
|
548
|
+
|
|
549
|
+
```javascript
|
|
550
|
+
import Roboto, {
|
|
551
|
+
RbtApi, // Low-level API client
|
|
552
|
+
RbtObject, // Object wrapper class
|
|
553
|
+
RbtFile, // File wrapper class
|
|
554
|
+
CookieStorageAdaptor // Cookie-based storage
|
|
555
|
+
} from 'roboto-js';
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
## Browser Compatibility
|
|
559
|
+
|
|
560
|
+
- Modern browsers with ES6+ support
|
|
561
|
+
- IndexedDB support for local caching
|
|
562
|
+
- WebSocket support for real-time features
|
|
563
|
+
- Cookie support for authentication
|
|
564
|
+
|
|
565
|
+
## Node.js Compatibility
|
|
566
|
+
|
|
567
|
+
- Node.js 14+ recommended
|
|
568
|
+
- ES Modules or CommonJS
|
|
569
|
+
- No browser-specific APIs used in core functionality
|
|
570
|
+
|
|
571
|
+
## License
|
|
572
|
+
|
|
573
|
+
ISC
|
|
574
|
+
|
|
575
|
+
## Version History
|
|
576
|
+
|
|
577
|
+
Current version: **1.9.5**
|
|
578
|
+
|
|
579
|
+
Version is automatically synced from `package.json` during build.
|
|
580
|
+
|
|
@@ -48,6 +48,16 @@ var CookieStorageAdaptor = exports["default"] = /*#__PURE__*/function () {
|
|
|
48
48
|
// Keys that should be stored without prefix for server-side access
|
|
49
49
|
serverAccessKeys: (_options$serverAccess = options.serverAccessKeys) !== null && _options$serverAccess !== void 0 ? _options$serverAccess : ['authtoken', 'accessKey', 'apikey']
|
|
50
50
|
}, options);
|
|
51
|
+
/*
|
|
52
|
+
console.log('[CookieStorageAdaptor] Initialized with options:', {
|
|
53
|
+
secure: this.options.secure,
|
|
54
|
+
sameSite: this.options.sameSite,
|
|
55
|
+
path: this.options.path,
|
|
56
|
+
maxAge: this.options.maxAge,
|
|
57
|
+
domain: this.options.domain,
|
|
58
|
+
prefix: this.options.prefix,
|
|
59
|
+
serverAccessKeys: this.options.serverAccessKeys
|
|
60
|
+
})*/
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
/**
|
|
@@ -72,7 +82,8 @@ var CookieStorageAdaptor = exports["default"] = /*#__PURE__*/function () {
|
|
|
72
82
|
cookieName = usePrefix ? this.options.prefix + key : key;
|
|
73
83
|
name = cookieName + '=';
|
|
74
84
|
decodedCookie = decodeURIComponent(document.cookie);
|
|
75
|
-
cookies = decodedCookie.split(';');
|
|
85
|
+
cookies = decodedCookie.split(';'); //console.log(`[CookieStorageAdaptor] getItem(${key}): looking for cookie "${cookieName}" ${usePrefix ? '(prefixed)' : '(server-accessible)'}`)
|
|
86
|
+
//console.log(`[CookieStorageAdaptor] Available cookies:`, cookies.map(c => c.trim().split('=')[0]).join(', '))
|
|
76
87
|
_iterator = _createForOfIteratorHelper(cookies);
|
|
77
88
|
_context.prev = 8;
|
|
78
89
|
_iterator.s();
|
|
@@ -87,9 +98,10 @@ var CookieStorageAdaptor = exports["default"] = /*#__PURE__*/function () {
|
|
|
87
98
|
_context.next = 23;
|
|
88
99
|
break;
|
|
89
100
|
}
|
|
90
|
-
rawValue = cookie.substring(name.length, cookie.length);
|
|
101
|
+
rawValue = cookie.substring(name.length, cookie.length); //console.log(`[CookieStorageAdaptor] Found cookie "${cookieName}" with raw value:`, rawValue)
|
|
102
|
+
// Handle JSON values (like rbtUser)
|
|
91
103
|
_context.prev = 15;
|
|
92
|
-
parsedValue = JSON.parse(rawValue);
|
|
104
|
+
parsedValue = JSON.parse(rawValue); //console.log(`[CookieStorageAdaptor] getItem(${key}): returning parsed JSON:`, parsedValue)
|
|
93
105
|
return _context.abrupt("return", parsedValue);
|
|
94
106
|
case 20:
|
|
95
107
|
_context.prev = 20;
|
|
@@ -143,12 +155,14 @@ var CookieStorageAdaptor = exports["default"] = /*#__PURE__*/function () {
|
|
|
143
155
|
// Check if this key should be stored without prefix for server access
|
|
144
156
|
usePrefix = !this.options.serverAccessKeys.includes(key);
|
|
145
157
|
cookieName = usePrefix ? this.options.prefix + key : key; // Stringify objects/arrays like localStorage does
|
|
146
|
-
cookieValue = _typeof(value) === 'object' ? JSON.stringify(value) : String(value);
|
|
158
|
+
cookieValue = _typeof(value) === 'object' ? JSON.stringify(value) : String(value); //console.log(`[CookieStorageAdaptor] setItem(${key}): storing as "${cookieName}" ${usePrefix ? '(prefixed)' : '(server-accessible)'}`)
|
|
159
|
+
//console.log(`[CookieStorageAdaptor] Original value:`, value)
|
|
160
|
+
//console.log(`[CookieStorageAdaptor] Cookie value:`, cookieValue)
|
|
147
161
|
// Build cookie string with security options
|
|
148
162
|
secureFlag = this.options.secure ? '; Secure' : '';
|
|
149
163
|
domainFlag = this.options.domain ? "; Domain=".concat(this.options.domain) : '';
|
|
150
164
|
httpOnlyFlag = this.options.httpOnly ? '; HttpOnly' : '';
|
|
151
|
-
cookieString = "".concat(cookieName, "=").concat(encodeURIComponent(cookieValue), "; path=").concat(this.options.path, "; max-age=").concat(this.options.maxAge, "; SameSite=").concat(this.options.sameSite).concat(secureFlag).concat(domainFlag).concat(httpOnlyFlag);
|
|
165
|
+
cookieString = "".concat(cookieName, "=").concat(encodeURIComponent(cookieValue), "; path=").concat(this.options.path, "; max-age=").concat(this.options.maxAge, "; SameSite=").concat(this.options.sameSite).concat(secureFlag).concat(domainFlag).concat(httpOnlyFlag); //console.log(`[CookieStorageAdaptor] Full cookie string:`, cookieString)
|
|
152
166
|
document.cookie = cookieString;
|
|
153
167
|
|
|
154
168
|
// Verify the cookie was set by immediately reading it back
|
|
@@ -190,7 +204,8 @@ var CookieStorageAdaptor = exports["default"] = /*#__PURE__*/function () {
|
|
|
190
204
|
case 2:
|
|
191
205
|
// Check if this key should be stored without prefix for server access
|
|
192
206
|
usePrefix = !this.options.serverAccessKeys.includes(key);
|
|
193
|
-
cookieName = usePrefix ? this.options.prefix + key : key;
|
|
207
|
+
cookieName = usePrefix ? this.options.prefix + key : key; //console.log(`[CookieStorageAdaptor] removeItem(${key}): removing cookie "${cookieName}" ${usePrefix ? '(prefixed)' : '(server-accessible)'}`)
|
|
208
|
+
// Check if cookie exists before removal
|
|
194
209
|
_context3.next = 6;
|
|
195
210
|
return this.getItem(key);
|
|
196
211
|
case 6:
|
|
@@ -198,7 +213,7 @@ var CookieStorageAdaptor = exports["default"] = /*#__PURE__*/function () {
|
|
|
198
213
|
if (existingValue !== null) {} else {}
|
|
199
214
|
secureFlag = this.options.secure ? '; Secure' : '';
|
|
200
215
|
domainFlag = this.options.domain ? "; Domain=".concat(this.options.domain) : '';
|
|
201
|
-
removalString = "".concat(cookieName, "=; path=").concat(this.options.path, "; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=").concat(this.options.sameSite).concat(secureFlag).concat(domainFlag);
|
|
216
|
+
removalString = "".concat(cookieName, "=; path=").concat(this.options.path, "; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=").concat(this.options.sameSite).concat(secureFlag).concat(domainFlag); //console.log(`[CookieStorageAdaptor] Removal cookie string:`, removalString)
|
|
202
217
|
document.cookie = removalString;
|
|
203
218
|
|
|
204
219
|
// Verify the cookie was removed
|