nodestack-client 1.3.0 → 2.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 +451 -341
- package/dist/Client.d.ts +11 -0
- package/dist/Client.d.ts.map +1 -1
- package/dist/auth/BaseAuthStore.d.ts.map +1 -1
- package/dist/auth/LocalAuthStore.d.ts.map +1 -1
- package/dist/auth/PkceUtil.d.ts +9 -0
- package/dist/auth/PkceUtil.d.ts.map +1 -0
- package/dist/errors/ClientResponseError.d.ts.map +1 -1
- package/dist/index.cjs +417 -8
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +417 -8
- package/dist/index.mjs.map +3 -3
- package/dist/services/AdminService.d.ts.map +1 -1
- package/dist/services/AppService.d.ts +30 -0
- package/dist/services/AppService.d.ts.map +1 -0
- package/dist/services/BaseService.d.ts +1 -0
- package/dist/services/BaseService.d.ts.map +1 -1
- package/dist/services/CollectionService.d.ts +2 -0
- package/dist/services/CollectionService.d.ts.map +1 -1
- package/dist/services/DemoService.d.ts.map +1 -1
- package/dist/services/FileService.d.ts +1 -0
- package/dist/services/FileService.d.ts.map +1 -1
- package/dist/services/RealtimeService.d.ts.map +1 -1
- package/dist/services/RecordService.d.ts +18 -1
- package/dist/services/RecordService.d.ts.map +1 -1
- package/dist/services/SnapshotService.d.ts +38 -0
- package/dist/services/SnapshotService.d.ts.map +1 -0
- package/dist/services/WebhookService.d.ts.map +1 -1
- package/dist/types.d.ts +119 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/Client.d.ts
CHANGED
|
@@ -5,7 +5,9 @@ import { RealtimeService } from './services/RealtimeService';
|
|
|
5
5
|
import { AdminService } from './services/AdminService';
|
|
6
6
|
import { CollectionService } from './services/CollectionService';
|
|
7
7
|
import { DemoService } from './services/DemoService';
|
|
8
|
+
import { SnapshotService } from './services/SnapshotService';
|
|
8
9
|
import { WebhookService } from './services/WebhookService';
|
|
10
|
+
import { AppService } from './services/AppService';
|
|
9
11
|
import type { ClientOptions, SendOptions, RecordModel, ChaosOptions } from './types';
|
|
10
12
|
/**
|
|
11
13
|
* Main NodeStack Client SDK entry point.
|
|
@@ -13,12 +15,16 @@ import type { ClientOptions, SendOptions, RecordModel, ChaosOptions } from './ty
|
|
|
13
15
|
export declare class NodeStackClient<TCollections extends Record<string, any> = Record<string, RecordModel>> {
|
|
14
16
|
readonly baseUrl: string;
|
|
15
17
|
readonly authStore: BaseAuthStore;
|
|
18
|
+
apiKey?: string;
|
|
16
19
|
readonly files: FileService;
|
|
17
20
|
readonly realtime: RealtimeService;
|
|
18
21
|
readonly admins: AdminService;
|
|
19
22
|
readonly collections: CollectionService;
|
|
23
|
+
readonly snapshots: SnapshotService;
|
|
20
24
|
readonly demo: DemoService;
|
|
21
25
|
readonly webhooks: WebhookService;
|
|
26
|
+
readonly apps: AppService;
|
|
27
|
+
readonly appSlug?: string;
|
|
22
28
|
private customFetch?;
|
|
23
29
|
private defaultHeaders;
|
|
24
30
|
private defaultTimeout;
|
|
@@ -65,5 +71,10 @@ export declare class NodeStackClient<TCollections extends Record<string, any> =
|
|
|
65
71
|
* Fetches system metrics & analytics (Admin only).
|
|
66
72
|
*/
|
|
67
73
|
metrics(): Promise<any>;
|
|
74
|
+
/**
|
|
75
|
+
* Returns a new NodeStackClient instance scoped to a specific application/MVP.
|
|
76
|
+
* Inherits baseUrl, authStore, customFetch, defaultHeaders, and defaultTimeout.
|
|
77
|
+
*/
|
|
78
|
+
app<TAppCollections extends Record<string, any> = Record<string, RecordModel>>(slug: string, options?: Partial<ClientOptions>): NodeStackClient<TAppCollections>;
|
|
68
79
|
}
|
|
69
80
|
//# sourceMappingURL=Client.d.ts.map
|
package/dist/Client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Client.d.ts","sourceRoot":"","sources":["../src/Client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EACV,aAAa,EACb,WAAW,EACX,WAAW,EACX,YAAY,EACb,MAAM,SAAS,CAAC;AAEjB;;GAEG;AACH,qBAAa,eAAe,CAAC,YAAY,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;IACjG,SAAgB,OAAO,EAAE,MAAM,CAAC;IAChC,SAAgB,SAAS,EAAE,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"Client.d.ts","sourceRoot":"","sources":["../src/Client.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseAuthStore.d.ts","sourceRoot":"","sources":["../../src/auth/BaseAuthStore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAExD,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,IAAI,KAAK,IAAI,CAAC;AAEjG;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAqC1E;AAED;;GAEG;AACH,8BAAsB,aAAa;IACjC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAM;IAC9B,SAAS,CAAC,MAAM,EAAE,WAAW,GAAG,UAAU,GAAG,IAAI,CAAQ;IACzD,OAAO,CAAC,UAAU,CAAsC;IAExD,IAAW,KAAK,IAAI,MAAM,CAEzB;IAED,IAAW,KAAK,IAAI,WAAW,GAAG,UAAU,GAAG,IAAI,CAElD;IAED;;OAEG;IACH,IAAW,OAAO,IAAI,OAAO,CAgB5B;IAED;;OAEG;IACI,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,UAAU,GAAG,IAAI,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"BaseAuthStore.d.ts","sourceRoot":"","sources":["../../src/auth/BaseAuthStore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAExD,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,IAAI,KAAK,IAAI,CAAC;AAEjG;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAqC1E;AAED;;GAEG;AACH,8BAAsB,aAAa;IACjC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAM;IAC9B,SAAS,CAAC,MAAM,EAAE,WAAW,GAAG,UAAU,GAAG,IAAI,CAAQ;IACzD,OAAO,CAAC,UAAU,CAAsC;IAExD,IAAW,KAAK,IAAI,MAAM,CAEzB;IAED,IAAW,KAAK,IAAI,WAAW,GAAG,UAAU,GAAG,IAAI,CAElD;IAED;;OAEG;IACH,IAAW,OAAO,IAAI,OAAO,CAgB5B;IAED;;OAEG;IACI,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,UAAU,GAAG,IAAI,GAAG,IAAI,CAIxE;IAED;;OAEG;IACI,KAAK,IAAI,IAAI,CAInB;IAED;;;OAGG;IACI,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,EAAE,eAAe,UAAQ,GAAG,MAAM,IAAI,CAajF;IAED;;OAEG;IACH,SAAS,CAAC,MAAM,IAAI,IAAI,CAQvB;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LocalAuthStore.d.ts","sourceRoot":"","sources":["../../src/auth/LocalAuthStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAExD,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACpC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAID;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,aAAa;IAC/C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAC,CAAc;
|
|
1
|
+
{"version":3,"file":"LocalAuthStore.d.ts","sourceRoot":"","sources":["../../src/auth/LocalAuthStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAExD,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACpC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAID;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,aAAa;IAC/C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAC,CAAc;IAE9B,YAAY,UAAU,GAAE,MAA4B,EAAE,aAAa,CAAC,EAAE,WAAW,EAWhF;IAED,OAAO,CAAC,WAAW;IAiBH,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,UAAU,GAAG,IAAI,GAAG,IAAI,CAgBjF;IAEe,KAAK,IAAI,IAAI,CAU5B;CACF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight, zero-dependency PKCE helper for browsers and Node.js environments.
|
|
3
|
+
*/
|
|
4
|
+
export declare class PkceUtil {
|
|
5
|
+
static generateVerifier(length?: number): string;
|
|
6
|
+
static generateChallenge(verifier: string): Promise<string>;
|
|
7
|
+
static base64UrlEncode(bytes: Uint8Array): string;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=PkceUtil.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PkceUtil.d.ts","sourceRoot":"","sources":["../../src/auth/PkceUtil.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,QAAQ;IACnB,OAAc,gBAAgB,CAAC,MAAM,SAAK,GAAG,MAAM,CAgClD;IAED,OAAoB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBvE;IAED,OAAc,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAiCvD;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClientResponseError.d.ts","sourceRoot":"","sources":["../../src/errors/ClientResponseError.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,0BAA0B;IACzC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,GAAG,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,SAAgB,GAAG,EAAE,MAAM,CAAC;IAC5B,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,IAAI,EAAE,GAAG,CAAC;IAC1B,SAAgB,OAAO,EAAE,OAAO,CAAC;IACjC,SAAgB,aAAa,CAAC,EAAE,GAAG,CAAC;
|
|
1
|
+
{"version":3,"file":"ClientResponseError.d.ts","sourceRoot":"","sources":["../../src/errors/ClientResponseError.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,0BAA0B;IACzC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,GAAG,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,SAAgB,GAAG,EAAE,MAAM,CAAC;IAC5B,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,IAAI,EAAE,GAAG,CAAC;IAC1B,SAAgB,OAAO,EAAE,OAAO,CAAC;IACjC,SAAgB,aAAa,CAAC,EAAE,GAAG,CAAC;IAEpC,YAAY,OAAO,GAAE,0BAA+B,EAiBnD;IAEM,MAAM;QAET,IAAI;QACJ,OAAO;QACP,GAAG;QACH,MAAM;QACN,IAAI;QACJ,OAAO;MAEV;CACF"}
|
package/dist/index.cjs
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
AdminService: () => AdminService,
|
|
24
|
+
AppService: () => AppService,
|
|
24
25
|
BaseAuthStore: () => BaseAuthStore,
|
|
25
26
|
BaseService: () => BaseService,
|
|
26
27
|
ClientResponseError: () => ClientResponseError,
|
|
@@ -30,8 +31,10 @@ __export(index_exports, {
|
|
|
30
31
|
LocalAuthStore: () => LocalAuthStore,
|
|
31
32
|
MemoryAuthStore: () => MemoryAuthStore,
|
|
32
33
|
NodeStackClient: () => NodeStackClient,
|
|
34
|
+
PkceUtil: () => PkceUtil,
|
|
33
35
|
RealtimeService: () => RealtimeService,
|
|
34
36
|
RecordService: () => RecordService,
|
|
37
|
+
SnapshotService: () => SnapshotService,
|
|
35
38
|
WebhookService: () => WebhookService,
|
|
36
39
|
computeWebhookSignature: () => computeWebhookSignature,
|
|
37
40
|
decodeJwtPayload: () => decodeJwtPayload,
|
|
@@ -375,6 +378,175 @@ var RecordService = class extends BaseService {
|
|
|
375
378
|
}
|
|
376
379
|
return result;
|
|
377
380
|
}
|
|
381
|
+
/**
|
|
382
|
+
* Returns a list of configured and enabled OAuth2 authentication providers.
|
|
383
|
+
*/
|
|
384
|
+
async listAuthMethods(redirectUri) {
|
|
385
|
+
return this.send(
|
|
386
|
+
`/api/collections/${encodeURIComponent(this.collectionName)}/auth-methods`,
|
|
387
|
+
{
|
|
388
|
+
method: "GET",
|
|
389
|
+
query: redirectUri ? { redirectUri } : void 0
|
|
390
|
+
}
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Authenticates against an auth collection using OAuth2 with PKCE code exchange.
|
|
395
|
+
* On success, automatically persists the token and record to authStore.
|
|
396
|
+
*/
|
|
397
|
+
async authWithOAuth2(options) {
|
|
398
|
+
let code = options.code;
|
|
399
|
+
let codeVerifier = options.codeVerifier;
|
|
400
|
+
if ((options.urlCallback || options.popup || typeof window !== "undefined" && !code && !codeVerifier) && (!code || !codeVerifier)) {
|
|
401
|
+
const authMethods = await this.listAuthMethods(options.redirectUrl);
|
|
402
|
+
const provider = authMethods.authProviders.find(
|
|
403
|
+
(p) => p.name.toLowerCase() === options.provider.toLowerCase()
|
|
404
|
+
);
|
|
405
|
+
if (!provider) {
|
|
406
|
+
throw new Error(`OAuth provider '${options.provider}' is not enabled or configured.`);
|
|
407
|
+
}
|
|
408
|
+
codeVerifier = provider.codeVerifier;
|
|
409
|
+
const expectedState = provider.state;
|
|
410
|
+
let expectedOrigin = null;
|
|
411
|
+
if (typeof window !== "undefined" && window.location) {
|
|
412
|
+
if (options.redirectUrl) {
|
|
413
|
+
try {
|
|
414
|
+
expectedOrigin = new URL(options.redirectUrl, window.location.href).origin;
|
|
415
|
+
} catch {
|
|
416
|
+
expectedOrigin = window.location.origin;
|
|
417
|
+
}
|
|
418
|
+
} else {
|
|
419
|
+
expectedOrigin = window.location.origin;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
let popup = options.popup || null;
|
|
423
|
+
if (options.urlCallback) {
|
|
424
|
+
const cbResult = options.urlCallback(provider.authUrl);
|
|
425
|
+
if (!popup && cbResult && typeof cbResult.postMessage === "function") {
|
|
426
|
+
popup = cbResult;
|
|
427
|
+
}
|
|
428
|
+
} else if (typeof window !== "undefined" && typeof window.open === "function") {
|
|
429
|
+
popup = window.open(provider.authUrl, "_blank", "width=600,height=700");
|
|
430
|
+
if (!popup) {
|
|
431
|
+
throw new Error("Failed to open OAuth popup window. It may have been blocked by the browser.");
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return new Promise((resolve, reject) => {
|
|
435
|
+
if (typeof window !== "undefined" && window.addEventListener) {
|
|
436
|
+
let pollTimer = null;
|
|
437
|
+
const cleanup = () => {
|
|
438
|
+
if (pollTimer) {
|
|
439
|
+
clearInterval(pollTimer);
|
|
440
|
+
pollTimer = null;
|
|
441
|
+
}
|
|
442
|
+
if (typeof window !== "undefined" && window.removeEventListener) {
|
|
443
|
+
window.removeEventListener("message", handler);
|
|
444
|
+
}
|
|
445
|
+
};
|
|
446
|
+
const handler = async (event) => {
|
|
447
|
+
if (!event.data || typeof event.data !== "object" || event.data.type !== "nodestack_oauth_callback") {
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
if (expectedOrigin && event.origin !== expectedOrigin) {
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
if (popup) {
|
|
454
|
+
if (event.source !== popup) {
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
} else if (event.source === window) {
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
if (expectedState && event.data.state !== expectedState) {
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
cleanup();
|
|
464
|
+
if (popup && typeof popup.close === "function") {
|
|
465
|
+
try {
|
|
466
|
+
popup.close();
|
|
467
|
+
} catch {
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (event.data.error) {
|
|
471
|
+
const errMsg = typeof event.data.error === "string" ? event.data.error : event.data.error.message || event.data.error_description || JSON.stringify(event.data.error);
|
|
472
|
+
return reject(new Error(errMsg));
|
|
473
|
+
}
|
|
474
|
+
if (!event.data.code) {
|
|
475
|
+
return reject(new Error("OAuth callback message is missing authorization code."));
|
|
476
|
+
}
|
|
477
|
+
try {
|
|
478
|
+
const res = await this.authWithOAuth2({
|
|
479
|
+
provider: options.provider,
|
|
480
|
+
code: event.data.code,
|
|
481
|
+
codeVerifier,
|
|
482
|
+
redirectUrl: options.redirectUrl,
|
|
483
|
+
createData: options.createData,
|
|
484
|
+
state: expectedState
|
|
485
|
+
});
|
|
486
|
+
resolve(res);
|
|
487
|
+
} catch (err) {
|
|
488
|
+
reject(err);
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
window.addEventListener("message", handler);
|
|
492
|
+
if (popup) {
|
|
493
|
+
pollTimer = setInterval(() => {
|
|
494
|
+
if (popup && popup.closed) {
|
|
495
|
+
cleanup();
|
|
496
|
+
reject(new Error("The OAuth popup window was closed before completing authentication."));
|
|
497
|
+
}
|
|
498
|
+
}, 500);
|
|
499
|
+
}
|
|
500
|
+
} else {
|
|
501
|
+
reject(new Error("urlCallback requires code and codeVerifier in non-browser environments."));
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
if (!code || !codeVerifier) {
|
|
506
|
+
throw new Error("Both code and codeVerifier are required for OAuth2 authentication");
|
|
507
|
+
}
|
|
508
|
+
const result = await this.send(
|
|
509
|
+
`/api/collections/${encodeURIComponent(this.collectionName)}/auth-with-oauth2`,
|
|
510
|
+
{
|
|
511
|
+
method: "POST",
|
|
512
|
+
body: {
|
|
513
|
+
provider: options.provider,
|
|
514
|
+
code,
|
|
515
|
+
codeVerifier,
|
|
516
|
+
state: options.state,
|
|
517
|
+
redirectUrl: options.redirectUrl,
|
|
518
|
+
createData: options.createData
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
);
|
|
522
|
+
if (result && result.token) {
|
|
523
|
+
this.client.authStore.save(result.token, result.record);
|
|
524
|
+
}
|
|
525
|
+
return result;
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Lists external social identities linked to a specific record.
|
|
529
|
+
*/
|
|
530
|
+
async listExternalAuths(recordId) {
|
|
531
|
+
return this.send(
|
|
532
|
+
`/api/collections/${encodeURIComponent(this.collectionName)}/records/${encodeURIComponent(recordId)}/external-auths`,
|
|
533
|
+
{
|
|
534
|
+
method: "GET"
|
|
535
|
+
}
|
|
536
|
+
);
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Unlinks an external social identity from a record.
|
|
540
|
+
*/
|
|
541
|
+
async unlinkExternalAuth(recordId, provider) {
|
|
542
|
+
await this.send(
|
|
543
|
+
`/api/collections/${encodeURIComponent(this.collectionName)}/records/${encodeURIComponent(recordId)}/external-auths/${encodeURIComponent(provider)}`,
|
|
544
|
+
{
|
|
545
|
+
method: "DELETE"
|
|
546
|
+
}
|
|
547
|
+
);
|
|
548
|
+
return true;
|
|
549
|
+
}
|
|
378
550
|
/**
|
|
379
551
|
* Exports records from the collection as CSV or JSON.
|
|
380
552
|
*/
|
|
@@ -466,7 +638,8 @@ var FileService = class extends BaseService {
|
|
|
466
638
|
const cleanCol = encodeURIComponent(collectionName);
|
|
467
639
|
const cleanId = encodeURIComponent(recordId);
|
|
468
640
|
const cleanFile = encodeURIComponent(filename);
|
|
469
|
-
|
|
641
|
+
const appSlug = options.app || this.client.appSlug;
|
|
642
|
+
let url = appSlug && appSlug !== "default" ? `${cleanBase}/api/apps/${encodeURIComponent(appSlug)}/files/${cleanCol}/${cleanId}/${cleanFile}` : `${cleanBase}/api/files/${cleanCol}/${cleanId}/${cleanFile}`;
|
|
470
643
|
const queryParts = [];
|
|
471
644
|
if (options.download) {
|
|
472
645
|
queryParts.push("download=1");
|
|
@@ -539,8 +712,16 @@ var RealtimeService = class extends BaseService {
|
|
|
539
712
|
const EventSourceClass = this.getEventSourceConstructor();
|
|
540
713
|
const base = (this.client.baseUrl || "").replace(/\/+$/, "");
|
|
541
714
|
let url = `${base}/api/realtime`;
|
|
715
|
+
const queryParams = new URLSearchParams();
|
|
542
716
|
if (this.client.authStore.token) {
|
|
543
|
-
|
|
717
|
+
queryParams.append("token", this.client.authStore.token);
|
|
718
|
+
}
|
|
719
|
+
if (this.client.appSlug) {
|
|
720
|
+
queryParams.append("app", this.client.appSlug);
|
|
721
|
+
}
|
|
722
|
+
const qs = queryParams.toString();
|
|
723
|
+
if (qs) {
|
|
724
|
+
url += `?${qs}`;
|
|
544
725
|
}
|
|
545
726
|
this.eventSource = new EventSourceClass(url);
|
|
546
727
|
const handleConnect = async (event) => {
|
|
@@ -772,6 +953,8 @@ var AdminService = class extends BaseService {
|
|
|
772
953
|
|
|
773
954
|
// src/services/CollectionService.ts
|
|
774
955
|
var CollectionService = class extends BaseService {
|
|
956
|
+
list = this.getList.bind(this);
|
|
957
|
+
get = this.getOne.bind(this);
|
|
775
958
|
/**
|
|
776
959
|
* Retrieves all collection schema models.
|
|
777
960
|
*/
|
|
@@ -878,11 +1061,72 @@ var DemoService = class extends BaseService {
|
|
|
878
1061
|
}
|
|
879
1062
|
};
|
|
880
1063
|
|
|
1064
|
+
// src/services/SnapshotService.ts
|
|
1065
|
+
var SnapshotService = class extends BaseService {
|
|
1066
|
+
/**
|
|
1067
|
+
* Retrieves all snapshots, active baseline, and live drift information.
|
|
1068
|
+
*/
|
|
1069
|
+
async list() {
|
|
1070
|
+
return this.send("/api/snapshots", {
|
|
1071
|
+
method: "GET"
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1074
|
+
/**
|
|
1075
|
+
* Alias for list() to retrieve status.
|
|
1076
|
+
*/
|
|
1077
|
+
async getStatus() {
|
|
1078
|
+
return this.list();
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* Creates a new application state snapshot.
|
|
1082
|
+
* If snapshot limit (10) is reached, evictOldest: true can be passed to confirm eviction of the oldest.
|
|
1083
|
+
*/
|
|
1084
|
+
async create(options) {
|
|
1085
|
+
return this.send("/api/snapshots", {
|
|
1086
|
+
method: "POST",
|
|
1087
|
+
body: options || {}
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
/**
|
|
1091
|
+
* Retrieves a specific snapshot by ID.
|
|
1092
|
+
*/
|
|
1093
|
+
async get(id) {
|
|
1094
|
+
return this.send(`/api/snapshots/${encodeURIComponent(id)}`, {
|
|
1095
|
+
method: "GET"
|
|
1096
|
+
});
|
|
1097
|
+
}
|
|
1098
|
+
/**
|
|
1099
|
+
* Restores application state to a specific snapshot.
|
|
1100
|
+
* Note: Future snapshots are NOT deleted; history remains intact.
|
|
1101
|
+
*/
|
|
1102
|
+
async restore(id) {
|
|
1103
|
+
return this.send(`/api/snapshots/${encodeURIComponent(id)}/restore`, {
|
|
1104
|
+
method: "POST"
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Deletes a specific snapshot by ID.
|
|
1109
|
+
*/
|
|
1110
|
+
async delete(id) {
|
|
1111
|
+
return this.send(`/api/snapshots/${encodeURIComponent(id)}`, {
|
|
1112
|
+
method: "DELETE"
|
|
1113
|
+
});
|
|
1114
|
+
}
|
|
1115
|
+
/**
|
|
1116
|
+
* Clears all saved snapshots.
|
|
1117
|
+
*/
|
|
1118
|
+
async clear() {
|
|
1119
|
+
return this.send("/api/snapshots", {
|
|
1120
|
+
method: "DELETE"
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
};
|
|
1124
|
+
|
|
881
1125
|
// src/services/WebhookService.ts
|
|
882
1126
|
function computeWebhookSignature(payload, secret) {
|
|
883
1127
|
const str = typeof payload === "string" ? payload : JSON.stringify(payload);
|
|
884
1128
|
try {
|
|
885
|
-
const nodeCrypto = typeof require !== "undefined" ? require("crypto") : globalThis?.crypto;
|
|
1129
|
+
const nodeCrypto = typeof require !== "undefined" ? require("crypto") : typeof globalThis !== "undefined" ? globalThis.require?.("crypto") || globalThis.crypto : null;
|
|
886
1130
|
if (nodeCrypto && typeof nodeCrypto.createHmac === "function") {
|
|
887
1131
|
return nodeCrypto.createHmac("sha256", secret).update(str, "utf8").digest("hex");
|
|
888
1132
|
}
|
|
@@ -906,9 +1150,10 @@ function verifyWebhookSignature(payload, signatureHeader, secret) {
|
|
|
906
1150
|
}
|
|
907
1151
|
if (cleanHeader.length !== expected.length) return false;
|
|
908
1152
|
try {
|
|
909
|
-
const nodeCrypto = typeof require !== "undefined" ? require("crypto") : null;
|
|
910
|
-
|
|
911
|
-
|
|
1153
|
+
const nodeCrypto = typeof require !== "undefined" ? require("crypto") : typeof globalThis !== "undefined" ? globalThis.require?.("crypto") : null;
|
|
1154
|
+
const buf = typeof Buffer !== "undefined" ? Buffer : typeof globalThis !== "undefined" ? globalThis.Buffer : null;
|
|
1155
|
+
if (nodeCrypto && typeof nodeCrypto.timingSafeEqual === "function" && buf) {
|
|
1156
|
+
return nodeCrypto.timingSafeEqual(buf.from(cleanHeader, "hex"), buf.from(expected, "hex"));
|
|
912
1157
|
}
|
|
913
1158
|
} catch {
|
|
914
1159
|
}
|
|
@@ -1035,16 +1280,70 @@ var WebhookService = class extends BaseService {
|
|
|
1035
1280
|
static computeSignature = computeWebhookSignature;
|
|
1036
1281
|
};
|
|
1037
1282
|
|
|
1283
|
+
// src/services/AppService.ts
|
|
1284
|
+
var AppService = class extends BaseService {
|
|
1285
|
+
list = this.getList.bind(this);
|
|
1286
|
+
get = this.getOne.bind(this);
|
|
1287
|
+
/**
|
|
1288
|
+
* Retrieves all configured applications.
|
|
1289
|
+
*/
|
|
1290
|
+
async getList() {
|
|
1291
|
+
const res = await this.send("/api/apps", {
|
|
1292
|
+
method: "GET"
|
|
1293
|
+
});
|
|
1294
|
+
return Array.isArray(res) ? res : res?.items || [];
|
|
1295
|
+
}
|
|
1296
|
+
/**
|
|
1297
|
+
* Retrieves a single application by ID or slug.
|
|
1298
|
+
*/
|
|
1299
|
+
async getOne(appId) {
|
|
1300
|
+
return this.send(`/api/apps/${encodeURIComponent(appId)}`, {
|
|
1301
|
+
method: "GET"
|
|
1302
|
+
});
|
|
1303
|
+
}
|
|
1304
|
+
/**
|
|
1305
|
+
* Creates a new application.
|
|
1306
|
+
*/
|
|
1307
|
+
async create(data) {
|
|
1308
|
+
return this.send("/api/apps", {
|
|
1309
|
+
method: "POST",
|
|
1310
|
+
body: data
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
1313
|
+
/**
|
|
1314
|
+
* Updates an existing application.
|
|
1315
|
+
*/
|
|
1316
|
+
async update(appId, data) {
|
|
1317
|
+
return this.send(`/api/apps/${encodeURIComponent(appId)}`, {
|
|
1318
|
+
method: "PATCH",
|
|
1319
|
+
body: data
|
|
1320
|
+
});
|
|
1321
|
+
}
|
|
1322
|
+
/**
|
|
1323
|
+
* Deletes an application by ID or slug.
|
|
1324
|
+
*/
|
|
1325
|
+
async delete(appId) {
|
|
1326
|
+
await this.send(`/api/apps/${encodeURIComponent(appId)}`, {
|
|
1327
|
+
method: "DELETE"
|
|
1328
|
+
});
|
|
1329
|
+
return true;
|
|
1330
|
+
}
|
|
1331
|
+
};
|
|
1332
|
+
|
|
1038
1333
|
// src/Client.ts
|
|
1039
|
-
var NodeStackClient = class {
|
|
1334
|
+
var NodeStackClient = class _NodeStackClient {
|
|
1040
1335
|
baseUrl;
|
|
1041
1336
|
authStore;
|
|
1337
|
+
apiKey;
|
|
1042
1338
|
files;
|
|
1043
1339
|
realtime;
|
|
1044
1340
|
admins;
|
|
1045
1341
|
collections;
|
|
1342
|
+
snapshots;
|
|
1046
1343
|
demo;
|
|
1047
1344
|
webhooks;
|
|
1345
|
+
apps;
|
|
1346
|
+
appSlug;
|
|
1048
1347
|
customFetch;
|
|
1049
1348
|
defaultHeaders;
|
|
1050
1349
|
defaultTimeout;
|
|
@@ -1053,16 +1352,20 @@ var NodeStackClient = class {
|
|
|
1053
1352
|
constructor(baseUrl = "/", options = {}) {
|
|
1054
1353
|
this.baseUrl = (baseUrl || "/").replace(/\/+$/, "");
|
|
1055
1354
|
this.authStore = options.authStore || new LocalAuthStore();
|
|
1355
|
+
this.apiKey = options.apiKey;
|
|
1056
1356
|
this.customFetch = options.fetch;
|
|
1057
1357
|
this.defaultHeaders = options.headers || {};
|
|
1058
1358
|
this.defaultTimeout = options.timeout || 12e4;
|
|
1059
1359
|
this.chaosOptions = options.chaos ? { ...options.chaos } : null;
|
|
1360
|
+
this.appSlug = options.app;
|
|
1060
1361
|
this.files = new FileService(this);
|
|
1061
1362
|
this.realtime = new RealtimeService(this, options.EventSource);
|
|
1062
1363
|
this.admins = new AdminService(this);
|
|
1063
1364
|
this.collections = new CollectionService(this);
|
|
1365
|
+
this.snapshots = new SnapshotService(this);
|
|
1064
1366
|
this.demo = new DemoService(this);
|
|
1065
1367
|
this.webhooks = new WebhookService(this);
|
|
1368
|
+
this.apps = new AppService(this);
|
|
1066
1369
|
}
|
|
1067
1370
|
/**
|
|
1068
1371
|
* Dynamically configure latency & chaos simulation options for all future requests.
|
|
@@ -1113,9 +1416,14 @@ var NodeStackClient = class {
|
|
|
1113
1416
|
...this.defaultHeaders,
|
|
1114
1417
|
...options.headers || {}
|
|
1115
1418
|
};
|
|
1116
|
-
if (this.
|
|
1419
|
+
if (this.apiKey && !headers["Authorization"] && !headers["authorization"] && !headers["x-api-key"] && !headers["X-API-Key"]) {
|
|
1420
|
+
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
1421
|
+
} else if (this.authStore.token && !headers["Authorization"] && !headers["authorization"]) {
|
|
1117
1422
|
headers["Authorization"] = `Bearer ${this.authStore.token}`;
|
|
1118
1423
|
}
|
|
1424
|
+
if (this.appSlug && !headers["x-nodestack-app"] && !headers["X-NodeStack-App"]) {
|
|
1425
|
+
headers["x-nodestack-app"] = this.appSlug;
|
|
1426
|
+
}
|
|
1119
1427
|
const effectiveChaos = {
|
|
1120
1428
|
...this.chaosOptions || {},
|
|
1121
1429
|
...options.chaos || {},
|
|
@@ -1232,10 +1540,111 @@ var NodeStackClient = class {
|
|
|
1232
1540
|
async metrics() {
|
|
1233
1541
|
return this.send("/api/metrics", { method: "GET" });
|
|
1234
1542
|
}
|
|
1543
|
+
/**
|
|
1544
|
+
* Returns a new NodeStackClient instance scoped to a specific application/MVP.
|
|
1545
|
+
* Inherits baseUrl, authStore, customFetch, defaultHeaders, and defaultTimeout.
|
|
1546
|
+
*/
|
|
1547
|
+
app(slug, options = {}) {
|
|
1548
|
+
return new _NodeStackClient(this.baseUrl, {
|
|
1549
|
+
authStore: options.authStore || this.authStore,
|
|
1550
|
+
fetch: options.fetch || this.customFetch,
|
|
1551
|
+
headers: { ...this.defaultHeaders, ...options.headers || {} },
|
|
1552
|
+
timeout: options.timeout !== void 0 ? options.timeout : this.defaultTimeout,
|
|
1553
|
+
chaos: options.chaos !== void 0 ? options.chaos ? { ...options.chaos } : void 0 : this.chaosOptions ? { ...this.chaosOptions } : void 0,
|
|
1554
|
+
app: slug,
|
|
1555
|
+
EventSource: options.EventSource || this.realtime.customEventSource
|
|
1556
|
+
});
|
|
1557
|
+
}
|
|
1235
1558
|
};
|
|
1236
1559
|
|
|
1237
1560
|
// src/auth/MemoryAuthStore.ts
|
|
1238
1561
|
var MemoryAuthStore = class extends BaseAuthStore {
|
|
1239
1562
|
// Inherits default in-memory behavior of BaseAuthStore
|
|
1240
1563
|
};
|
|
1564
|
+
|
|
1565
|
+
// src/auth/PkceUtil.ts
|
|
1566
|
+
var PkceUtil = class _PkceUtil {
|
|
1567
|
+
static generateVerifier(length = 64) {
|
|
1568
|
+
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
|
|
1569
|
+
const clampedLength = Math.max(43, Math.min(128, length));
|
|
1570
|
+
const randomBytes = new Uint8Array(clampedLength);
|
|
1571
|
+
const g = typeof globalThis !== "undefined" ? globalThis : {};
|
|
1572
|
+
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
|
1573
|
+
crypto.getRandomValues(randomBytes);
|
|
1574
|
+
} else if (g.crypto && g.crypto.getRandomValues) {
|
|
1575
|
+
g.crypto.getRandomValues(randomBytes);
|
|
1576
|
+
} else {
|
|
1577
|
+
let filled = false;
|
|
1578
|
+
try {
|
|
1579
|
+
const req = g.require;
|
|
1580
|
+
if (typeof req === "function") {
|
|
1581
|
+
req("crypto").randomFillSync(randomBytes);
|
|
1582
|
+
filled = true;
|
|
1583
|
+
}
|
|
1584
|
+
} catch {
|
|
1585
|
+
}
|
|
1586
|
+
if (!filled) {
|
|
1587
|
+
throw new Error(
|
|
1588
|
+
"A cryptographically secure random number generator (crypto.getRandomValues or node:crypto) is required to generate a PKCE code_verifier."
|
|
1589
|
+
);
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
let result = "";
|
|
1593
|
+
for (let i = 0; i < clampedLength; i++) {
|
|
1594
|
+
result += charset[randomBytes[i] % charset.length];
|
|
1595
|
+
}
|
|
1596
|
+
return result;
|
|
1597
|
+
}
|
|
1598
|
+
static async generateChallenge(verifier) {
|
|
1599
|
+
const encoder = new TextEncoder();
|
|
1600
|
+
const data = encoder.encode(verifier);
|
|
1601
|
+
const g = typeof globalThis !== "undefined" ? globalThis : {};
|
|
1602
|
+
if (typeof crypto !== "undefined" && crypto.subtle) {
|
|
1603
|
+
const hash = await crypto.subtle.digest("SHA-256", data);
|
|
1604
|
+
return _PkceUtil.base64UrlEncode(new Uint8Array(hash));
|
|
1605
|
+
} else if (g.crypto && g.crypto.subtle) {
|
|
1606
|
+
const hash = await g.crypto.subtle.digest("SHA-256", data);
|
|
1607
|
+
return _PkceUtil.base64UrlEncode(new Uint8Array(hash));
|
|
1608
|
+
}
|
|
1609
|
+
try {
|
|
1610
|
+
const req = g.require;
|
|
1611
|
+
if (typeof req === "function") {
|
|
1612
|
+
const hash = req("crypto").createHash("sha256").update(data).digest();
|
|
1613
|
+
return _PkceUtil.base64UrlEncode(new Uint8Array(hash));
|
|
1614
|
+
}
|
|
1615
|
+
} catch {
|
|
1616
|
+
}
|
|
1617
|
+
throw new Error("Web Crypto API (crypto.subtle) is not available to compute SHA-256 code challenge.");
|
|
1618
|
+
}
|
|
1619
|
+
static base64UrlEncode(bytes) {
|
|
1620
|
+
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
1621
|
+
let base64 = "";
|
|
1622
|
+
const byteLength = bytes.byteLength;
|
|
1623
|
+
const byteRemainder = byteLength % 3;
|
|
1624
|
+
const mainLength = byteLength - byteRemainder;
|
|
1625
|
+
let a, b, c, d;
|
|
1626
|
+
let chunk;
|
|
1627
|
+
for (let i = 0; i < mainLength; i += 3) {
|
|
1628
|
+
chunk = bytes[i] << 16 | bytes[i + 1] << 8 | bytes[i + 2];
|
|
1629
|
+
a = (chunk & 16515072) >> 18;
|
|
1630
|
+
b = (chunk & 258048) >> 12;
|
|
1631
|
+
c = (chunk & 4032) >> 6;
|
|
1632
|
+
d = chunk & 63;
|
|
1633
|
+
base64 += chars[a] + chars[b] + chars[c] + chars[d];
|
|
1634
|
+
}
|
|
1635
|
+
if (byteRemainder === 1) {
|
|
1636
|
+
chunk = bytes[mainLength];
|
|
1637
|
+
a = (chunk & 252) >> 2;
|
|
1638
|
+
b = (chunk & 3) << 4;
|
|
1639
|
+
base64 += chars[a] + chars[b] + "==";
|
|
1640
|
+
} else if (byteRemainder === 2) {
|
|
1641
|
+
chunk = bytes[mainLength] << 8 | bytes[mainLength + 1];
|
|
1642
|
+
a = (chunk & 64512) >> 10;
|
|
1643
|
+
b = (chunk & 1008) >> 4;
|
|
1644
|
+
c = (chunk & 15) << 2;
|
|
1645
|
+
base64 += chars[a] + chars[b] + chars[c] + "=";
|
|
1646
|
+
}
|
|
1647
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
1648
|
+
}
|
|
1649
|
+
};
|
|
1241
1650
|
//# sourceMappingURL=index.cjs.map
|