@stratum-hq/sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/client.test.d.ts +2 -0
- package/dist/__tests__/client.test.d.ts.map +1 -0
- package/dist/__tests__/client.test.js +303 -0
- package/dist/__tests__/client.test.js.map +1 -0
- package/dist/__tests__/context.test.d.ts +2 -0
- package/dist/__tests__/context.test.d.ts.map +1 -0
- package/dist/__tests__/context.test.js +117 -0
- package/dist/__tests__/context.test.js.map +1 -0
- package/dist/__tests__/middleware-express.test.d.ts +2 -0
- package/dist/__tests__/middleware-express.test.d.ts.map +1 -0
- package/dist/__tests__/middleware-express.test.js +189 -0
- package/dist/__tests__/middleware-express.test.js.map +1 -0
- package/dist/__tests__/middleware-fastify.test.d.ts +2 -0
- package/dist/__tests__/middleware-fastify.test.d.ts.map +1 -0
- package/dist/__tests__/middleware-fastify.test.js +266 -0
- package/dist/__tests__/middleware-fastify.test.js.map +1 -0
- package/dist/cache.d.ts +14 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +47 -0
- package/dist/cache.js.map +1 -0
- package/dist/client.d.ts +60 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +176 -0
- package/dist/client.js.map +1 -0
- package/dist/context.d.ts +8 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +24 -0
- package/dist/context.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/express.d.ts +4 -0
- package/dist/middleware/express.d.ts.map +1 -0
- package/dist/middleware/express.js +58 -0
- package/dist/middleware/express.js.map +1 -0
- package/dist/middleware/fastify.d.ts +6 -0
- package/dist/middleware/fastify.d.ts.map +1 -0
- package/dist/middleware/fastify.js +58 -0
- package/dist/middleware/fastify.js.map +1 -0
- package/dist/resolvers/custom.d.ts +4 -0
- package/dist/resolvers/custom.d.ts.map +1 -0
- package/dist/resolvers/custom.js +3 -0
- package/dist/resolvers/custom.js.map +1 -0
- package/dist/resolvers/header.d.ts +2 -0
- package/dist/resolvers/header.d.ts.map +1 -0
- package/dist/resolvers/header.js +16 -0
- package/dist/resolvers/header.js.map +1 -0
- package/dist/resolvers/jwt.d.ts +6 -0
- package/dist/resolvers/jwt.d.ts.map +1 -0
- package/dist/resolvers/jwt.js +55 -0
- package/dist/resolvers/jwt.js.map +1 -0
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +39 -0
package/dist/client.js
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StratumClient = void 0;
|
|
4
|
+
const core_1 = require("@stratum-hq/core");
|
|
5
|
+
const cache_js_1 = require("./cache.js");
|
|
6
|
+
class StratumClient {
|
|
7
|
+
baseUrl;
|
|
8
|
+
apiKey;
|
|
9
|
+
regionUrl;
|
|
10
|
+
cache;
|
|
11
|
+
cacheEnabled;
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.baseUrl = options.controlPlaneUrl.replace(/\/$/, "");
|
|
14
|
+
this.apiKey = options.apiKey;
|
|
15
|
+
this.regionUrl = options.regionUrl?.replace(/\/$/, "");
|
|
16
|
+
this.cacheEnabled = options.cache?.enabled !== false;
|
|
17
|
+
this.cache = new cache_js_1.LRUCache({
|
|
18
|
+
ttlMs: options.cache?.ttlMs,
|
|
19
|
+
maxSize: options.cache?.maxSize,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
async fetch(path, init) {
|
|
23
|
+
const url = `${this.baseUrl}${path}`;
|
|
24
|
+
const response = await globalThis.fetch(url, {
|
|
25
|
+
...init,
|
|
26
|
+
headers: {
|
|
27
|
+
"Content-Type": "application/json",
|
|
28
|
+
"X-API-Key": this.apiKey,
|
|
29
|
+
...init?.headers,
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
if (response.status === 401) {
|
|
34
|
+
throw new core_1.UnauthorizedError("Invalid or missing API key");
|
|
35
|
+
}
|
|
36
|
+
if (response.status === 404) {
|
|
37
|
+
const body = await response.json().catch(() => ({}));
|
|
38
|
+
throw new core_1.TenantNotFoundError(body?.error?.message ?? "unknown");
|
|
39
|
+
}
|
|
40
|
+
const body = await response.json().catch(() => ({}));
|
|
41
|
+
throw new Error(body?.error?.message ?? `HTTP ${response.status}`);
|
|
42
|
+
}
|
|
43
|
+
if (response.status === 204)
|
|
44
|
+
return undefined;
|
|
45
|
+
return response.json();
|
|
46
|
+
}
|
|
47
|
+
async resolveTenant(tenantId) {
|
|
48
|
+
if (this.cacheEnabled) {
|
|
49
|
+
const cached = this.cache.get(tenantId);
|
|
50
|
+
if (cached)
|
|
51
|
+
return cached;
|
|
52
|
+
}
|
|
53
|
+
const context = await this.fetch(`/api/v1/tenants/${tenantId}/context`);
|
|
54
|
+
if (this.cacheEnabled) {
|
|
55
|
+
this.cache.set(tenantId, context);
|
|
56
|
+
}
|
|
57
|
+
return context;
|
|
58
|
+
}
|
|
59
|
+
async getTenantTree(rootId) {
|
|
60
|
+
if (rootId) {
|
|
61
|
+
return this.fetch(`/api/v1/tenants/${rootId}/descendants`);
|
|
62
|
+
}
|
|
63
|
+
const result = await this.fetch(`/api/v1/tenants`);
|
|
64
|
+
return result.data;
|
|
65
|
+
}
|
|
66
|
+
async createTenant(input) {
|
|
67
|
+
return this.fetch("/api/v1/tenants", {
|
|
68
|
+
method: "POST",
|
|
69
|
+
body: JSON.stringify(input),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
async getTenant(tenantId) {
|
|
73
|
+
return this.fetch(`/api/v1/tenants/${tenantId}`);
|
|
74
|
+
}
|
|
75
|
+
async updateTenant(tenantId, input) {
|
|
76
|
+
const node = await this.fetch(`/api/v1/tenants/${tenantId}`, {
|
|
77
|
+
method: "PATCH",
|
|
78
|
+
body: JSON.stringify(input),
|
|
79
|
+
});
|
|
80
|
+
this.cache.invalidate(tenantId);
|
|
81
|
+
return node;
|
|
82
|
+
}
|
|
83
|
+
async moveTenant(tenantId, input) {
|
|
84
|
+
const node = await this.fetch(`/api/v1/tenants/${tenantId}/move`, {
|
|
85
|
+
method: "POST",
|
|
86
|
+
body: JSON.stringify(input),
|
|
87
|
+
});
|
|
88
|
+
this.cache.invalidate(tenantId);
|
|
89
|
+
return node;
|
|
90
|
+
}
|
|
91
|
+
async archiveTenant(tenantId) {
|
|
92
|
+
await this.fetch(`/api/v1/tenants/${tenantId}`, {
|
|
93
|
+
method: "DELETE",
|
|
94
|
+
});
|
|
95
|
+
this.cache.invalidate(tenantId);
|
|
96
|
+
}
|
|
97
|
+
async deleteTenant(tenantId) {
|
|
98
|
+
await this.fetch(`/api/v1/tenants/${tenantId}`, {
|
|
99
|
+
method: "DELETE",
|
|
100
|
+
});
|
|
101
|
+
this.cache.invalidate(tenantId);
|
|
102
|
+
}
|
|
103
|
+
invalidateCache(tenantId) {
|
|
104
|
+
this.cache.invalidate(tenantId);
|
|
105
|
+
}
|
|
106
|
+
clearCache() {
|
|
107
|
+
this.cache.clear();
|
|
108
|
+
}
|
|
109
|
+
async createWebhook(input) {
|
|
110
|
+
return this.fetch("/api/v1/webhooks", {
|
|
111
|
+
method: "POST",
|
|
112
|
+
body: JSON.stringify(input),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
async listWebhooks(tenantId) {
|
|
116
|
+
const path = tenantId
|
|
117
|
+
? `/api/v1/webhooks?tenant_id=${encodeURIComponent(tenantId)}`
|
|
118
|
+
: "/api/v1/webhooks";
|
|
119
|
+
return this.fetch(path);
|
|
120
|
+
}
|
|
121
|
+
async getWebhook(id) {
|
|
122
|
+
return this.fetch(`/api/v1/webhooks/${id}`);
|
|
123
|
+
}
|
|
124
|
+
async updateWebhook(id, input) {
|
|
125
|
+
return this.fetch(`/api/v1/webhooks/${id}`, {
|
|
126
|
+
method: "PATCH",
|
|
127
|
+
body: JSON.stringify(input),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
async deleteWebhook(id) {
|
|
131
|
+
await this.fetch(`/api/v1/webhooks/${id}`, {
|
|
132
|
+
method: "DELETE",
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
async rotateApiKey(keyId, name) {
|
|
136
|
+
return this.fetch(`/api/v1/api-keys/${keyId}/rotate`, {
|
|
137
|
+
method: "POST",
|
|
138
|
+
body: JSON.stringify(name ? { name } : {}),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
async listApiKeys(tenantId) {
|
|
142
|
+
const path = tenantId
|
|
143
|
+
? `/api/v1/api-keys?tenant_id=${encodeURIComponent(tenantId)}`
|
|
144
|
+
: "/api/v1/api-keys";
|
|
145
|
+
return this.fetch(path);
|
|
146
|
+
}
|
|
147
|
+
async listDormantKeys(days) {
|
|
148
|
+
const path = days
|
|
149
|
+
? `/api/v1/api-keys/dormant?days=${days}`
|
|
150
|
+
: "/api/v1/api-keys/dormant";
|
|
151
|
+
return this.fetch(path);
|
|
152
|
+
}
|
|
153
|
+
// Region operations
|
|
154
|
+
async listRegions() {
|
|
155
|
+
return this.fetch("/api/v1/regions");
|
|
156
|
+
}
|
|
157
|
+
async createRegion(input) {
|
|
158
|
+
return this.fetch("/api/v1/regions", {
|
|
159
|
+
method: "POST",
|
|
160
|
+
body: JSON.stringify(input),
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
async updateRegion(id, input) {
|
|
164
|
+
return this.fetch(`/api/v1/regions/${id}`, {
|
|
165
|
+
method: "PATCH",
|
|
166
|
+
body: JSON.stringify(input),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
async deleteRegion(id) {
|
|
170
|
+
await this.fetch(`/api/v1/regions/${id}`, {
|
|
171
|
+
method: "DELETE",
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
exports.StratumClient = StratumClient;
|
|
176
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":";;;AAAA,2CAA0E;AAE1E,yCAAsC;AAStC,MAAa,aAAa;IACP,OAAO,CAAS;IAChB,MAAM,CAAS;IACf,SAAS,CAAqB;IAC9B,KAAK,CAAwC;IAC7C,YAAY,CAAU;IAEvC,YAAY,OAA6B;QACvC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC1D,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACvD,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,KAAK,EAAE,OAAO,KAAK,KAAK,CAAC;QACrD,IAAI,CAAC,KAAK,GAAG,IAAI,mBAAQ,CAA8B;YACrD,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK;YAC3B,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO;SAChC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,KAAK,CAAI,IAAY,EAAE,IAAkB;QACrD,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,GAAG,EAAE;YAC3C,GAAG,IAAI;YACP,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,WAAW,EAAE,IAAI,CAAC,MAAM;gBACxB,GAAI,IAAI,EAAE,OAA8C;aACzD;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC5B,MAAM,IAAI,wBAAiB,CAAC,4BAA4B,CAAC,CAAC;YAC5D,CAAC;YACD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC5B,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAqC,CAAC;gBACzF,MAAM,IAAI,0BAAmB,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,IAAI,SAAS,CAAC,CAAC;YACnE,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAqC,CAAC;YACzF,MAAM,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,IAAI,QAAQ,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QACrE,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,SAAc,CAAC;QACnD,OAAO,QAAQ,CAAC,IAAI,EAAgB,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,QAAgB;QAClC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACxC,IAAI,MAAM;gBAAE,OAAO,MAAM,CAAC;QAC5B,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAsB,mBAAmB,QAAQ,UAAU,CAAC,CAAC;QAC7F,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACpC,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,MAAe;QACjC,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,IAAI,CAAC,KAAK,CAAe,mBAAmB,MAAM,cAAc,CAAC,CAAC;QAC3E,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAyB,iBAAiB,CAAC,CAAC;QAC3E,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAAwB;QACzC,OAAO,IAAI,CAAC,KAAK,CAAa,iBAAiB,EAAE;YAC/C,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,QAAgB;QAC9B,OAAO,IAAI,CAAC,KAAK,CAAa,mBAAmB,QAAQ,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,QAAgB,EAAE,KAAwB;QAC3D,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAa,mBAAmB,QAAQ,EAAE,EAAE;YACvE,MAAM,EAAE,OAAO;YACf,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;SAC5B,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,QAAgB,EAAE,KAAsB;QACvD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAa,mBAAmB,QAAQ,OAAO,EAAE;YAC5E,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;SAC5B,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,QAAgB;QAClC,MAAM,IAAI,CAAC,KAAK,CAAO,mBAAmB,QAAQ,EAAE,EAAE;YACpD,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,QAAgB;QACjC,MAAM,IAAI,CAAC,KAAK,CAAO,mBAAmB,QAAQ,EAAE,EAAE;YACpD,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;IAED,eAAe,CAAC,QAAgB;QAC9B,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;IAED,UAAU;QACR,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,KAAyB;QAC3C,OAAO,IAAI,CAAC,KAAK,CAAU,kBAAkB,EAAE;YAC7C,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,QAAiB;QAClC,MAAM,IAAI,GAAG,QAAQ;YACnB,CAAC,CAAC,8BAA8B,kBAAkB,CAAC,QAAQ,CAAC,EAAE;YAC9D,CAAC,CAAC,kBAAkB,CAAC;QACvB,OAAO,IAAI,CAAC,KAAK,CAAY,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,EAAU;QACzB,OAAO,IAAI,CAAC,KAAK,CAAU,oBAAoB,EAAE,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,EAAU,EAAE,KAAyB;QACvD,OAAO,IAAI,CAAC,KAAK,CAAU,oBAAoB,EAAE,EAAE,EAAE;YACnD,MAAM,EAAE,OAAO;YACf,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,EAAU;QAC5B,MAAM,IAAI,CAAC,KAAK,CAAO,oBAAoB,EAAE,EAAE,EAAE;YAC/C,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAAa,EAAE,IAAa;QAC7C,OAAO,IAAI,CAAC,KAAK,CAAC,oBAAoB,KAAK,SAAS,EAAE;YACpD,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC3C,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,QAAiB;QACjC,MAAM,IAAI,GAAG,QAAQ;YACnB,CAAC,CAAC,8BAA8B,kBAAkB,CAAC,QAAQ,CAAC,EAAE;YAC9D,CAAC,CAAC,kBAAkB,CAAC;QACvB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,IAAa;QACjC,MAAM,IAAI,GAAG,IAAI;YACf,CAAC,CAAC,iCAAiC,IAAI,EAAE;YACzC,CAAC,CAAC,0BAA0B,CAAC;QAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,oBAAoB;IACpB,KAAK,CAAC,WAAW;QACf,OAAO,IAAI,CAAC,KAAK,CAAW,iBAAiB,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAAwB;QACzC,OAAO,IAAI,CAAC,KAAK,CAAS,iBAAiB,EAAE;YAC3C,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,EAAU,EAAE,KAAwB;QACrD,OAAO,IAAI,CAAC,KAAK,CAAS,mBAAmB,EAAE,EAAE,EAAE;YACjD,MAAM,EAAE,OAAO;YACf,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,EAAU;QAC3B,MAAM,IAAI,CAAC,KAAK,CAAO,mBAAmB,EAAE,EAAE,EAAE;YAC9C,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAC;IACL,CAAC;CACF;AAjMD,sCAiMC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
+
import type { TenantContextLegacy } from "@stratum-hq/core";
|
|
4
|
+
export declare const tenantStorage: AsyncLocalStorage<TenantContextLegacy>;
|
|
5
|
+
export declare function getTenantContext(): TenantContextLegacy;
|
|
6
|
+
export declare function runWithTenantContext<T>(context: TenantContextLegacy, fn: () => T): T;
|
|
7
|
+
export declare function setTenantContext(context: TenantContextLegacy): void;
|
|
8
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE5D,eAAO,MAAM,aAAa,wCAA+C,CAAC;AAE1E,wBAAgB,gBAAgB,IAAI,mBAAmB,CAMtD;AAED,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,OAAO,EAAE,mBAAmB,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAEpF;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAGnE"}
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setTenantContext = exports.runWithTenantContext = exports.getTenantContext = exports.tenantStorage = void 0;
|
|
4
|
+
const node_async_hooks_1 = require("node:async_hooks");
|
|
5
|
+
const core_1 = require("@stratum-hq/core");
|
|
6
|
+
exports.tenantStorage = new node_async_hooks_1.AsyncLocalStorage();
|
|
7
|
+
function getTenantContext() {
|
|
8
|
+
const ctx = exports.tenantStorage.getStore();
|
|
9
|
+
if (!ctx) {
|
|
10
|
+
throw new core_1.TenantContextNotFoundError();
|
|
11
|
+
}
|
|
12
|
+
return ctx;
|
|
13
|
+
}
|
|
14
|
+
exports.getTenantContext = getTenantContext;
|
|
15
|
+
function runWithTenantContext(context, fn) {
|
|
16
|
+
return exports.tenantStorage.run(context, fn);
|
|
17
|
+
}
|
|
18
|
+
exports.runWithTenantContext = runWithTenantContext;
|
|
19
|
+
function setTenantContext(context) {
|
|
20
|
+
// Bind the current store value — for middleware entry points
|
|
21
|
+
exports.tenantStorage.enterWith(context);
|
|
22
|
+
}
|
|
23
|
+
exports.setTenantContext = setTenantContext;
|
|
24
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":";;;AAAA,uDAAqD;AACrD,2CAA8D;AAGjD,QAAA,aAAa,GAAG,IAAI,oCAAiB,EAAuB,CAAC;AAE1E,SAAgB,gBAAgB;IAC9B,MAAM,GAAG,GAAG,qBAAa,CAAC,QAAQ,EAAE,CAAC;IACrC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,iCAA0B,EAAE,CAAC;IACzC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAND,4CAMC;AAED,SAAgB,oBAAoB,CAAI,OAA4B,EAAE,EAAW;IAC/E,OAAO,qBAAa,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AACxC,CAAC;AAFD,oDAEC;AAED,SAAgB,gBAAgB,CAAC,OAA4B;IAC3D,6DAA6D;IAC7D,qBAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;AACnC,CAAC;AAHD,4CAGC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { StratumClient } from "./client.js";
|
|
2
|
+
import type { StratumClientOptions } from "./client.js";
|
|
3
|
+
import { getTenantContext, runWithTenantContext } from "./context.js";
|
|
4
|
+
import type { MiddlewareOptions } from "./types.js";
|
|
5
|
+
export declare function stratum(options: StratumClientOptions): {
|
|
6
|
+
client: StratumClient;
|
|
7
|
+
middleware: (opts?: MiddlewareOptions) => (req: any, res: any, next: any) => Promise<void>;
|
|
8
|
+
plugin: (opts?: MiddlewareOptions) => (fastify: any, _opts: any, done: any) => void;
|
|
9
|
+
getTenantContext: typeof getTenantContext;
|
|
10
|
+
runWithTenantContext: typeof runWithTenantContext;
|
|
11
|
+
};
|
|
12
|
+
export { StratumClient } from "./client.js";
|
|
13
|
+
export type { StratumClientOptions } from "./client.js";
|
|
14
|
+
export { getTenantContext, runWithTenantContext, setTenantContext, tenantStorage } from "./context.js";
|
|
15
|
+
export { expressMiddleware } from "./middleware/express.js";
|
|
16
|
+
export { fastifyPlugin } from "./middleware/fastify.js";
|
|
17
|
+
export { resolveFromHeader } from "./resolvers/header.js";
|
|
18
|
+
export { resolveFromJwt } from "./resolvers/jwt.js";
|
|
19
|
+
export type { TenantResolver } from "./resolvers/custom.js";
|
|
20
|
+
export type { MiddlewareOptions } from "./types.js";
|
|
21
|
+
export type { TenantContextLegacy, TenantNode, CreateTenantInput, UpdateTenantInput, MoveTenantInput, ResolvedPermission, } from "@stratum-hq/core";
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGxD,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,wBAAgB,OAAO,CAAC,OAAO,EAAE,oBAAoB;;wBAI7B,iBAAiB;oBACrB,iBAAiB,eACrB,GAAG,SAAS,GAAG,QAAQ,GAAG;;;EAKzC;AAGD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,YAAY,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACvG,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,YAAY,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAGpD,YAAY,EACV,mBAAmB,EACnB,UAAU,EACV,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,kBAAkB,GACnB,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveFromJwt = exports.resolveFromHeader = exports.fastifyPlugin = exports.expressMiddleware = exports.tenantStorage = exports.setTenantContext = exports.runWithTenantContext = exports.getTenantContext = exports.StratumClient = exports.stratum = void 0;
|
|
4
|
+
const client_js_1 = require("./client.js");
|
|
5
|
+
const express_js_1 = require("./middleware/express.js");
|
|
6
|
+
const fastify_js_1 = require("./middleware/fastify.js");
|
|
7
|
+
const context_js_1 = require("./context.js");
|
|
8
|
+
function stratum(options) {
|
|
9
|
+
const client = new client_js_1.StratumClient(options);
|
|
10
|
+
return {
|
|
11
|
+
client,
|
|
12
|
+
middleware: (opts) => (0, express_js_1.expressMiddleware)(client, opts),
|
|
13
|
+
plugin: (opts) => (fastify, _opts, done) => (0, fastify_js_1.fastifyPlugin)(fastify, { client, ...opts }, done),
|
|
14
|
+
getTenantContext: context_js_1.getTenantContext,
|
|
15
|
+
runWithTenantContext: context_js_1.runWithTenantContext,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
exports.stratum = stratum;
|
|
19
|
+
// Named exports for direct usage
|
|
20
|
+
var client_js_2 = require("./client.js");
|
|
21
|
+
Object.defineProperty(exports, "StratumClient", { enumerable: true, get: function () { return client_js_2.StratumClient; } });
|
|
22
|
+
var context_js_2 = require("./context.js");
|
|
23
|
+
Object.defineProperty(exports, "getTenantContext", { enumerable: true, get: function () { return context_js_2.getTenantContext; } });
|
|
24
|
+
Object.defineProperty(exports, "runWithTenantContext", { enumerable: true, get: function () { return context_js_2.runWithTenantContext; } });
|
|
25
|
+
Object.defineProperty(exports, "setTenantContext", { enumerable: true, get: function () { return context_js_2.setTenantContext; } });
|
|
26
|
+
Object.defineProperty(exports, "tenantStorage", { enumerable: true, get: function () { return context_js_2.tenantStorage; } });
|
|
27
|
+
var express_js_2 = require("./middleware/express.js");
|
|
28
|
+
Object.defineProperty(exports, "expressMiddleware", { enumerable: true, get: function () { return express_js_2.expressMiddleware; } });
|
|
29
|
+
var fastify_js_2 = require("./middleware/fastify.js");
|
|
30
|
+
Object.defineProperty(exports, "fastifyPlugin", { enumerable: true, get: function () { return fastify_js_2.fastifyPlugin; } });
|
|
31
|
+
var header_js_1 = require("./resolvers/header.js");
|
|
32
|
+
Object.defineProperty(exports, "resolveFromHeader", { enumerable: true, get: function () { return header_js_1.resolveFromHeader; } });
|
|
33
|
+
var jwt_js_1 = require("./resolvers/jwt.js");
|
|
34
|
+
Object.defineProperty(exports, "resolveFromJwt", { enumerable: true, get: function () { return jwt_js_1.resolveFromJwt; } });
|
|
35
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,2CAA4C;AAE5C,wDAA4D;AAC5D,wDAAwD;AACxD,6CAAsE;AAGtE,SAAgB,OAAO,CAAC,OAA6B;IACnD,MAAM,MAAM,GAAG,IAAI,yBAAa,CAAC,OAAO,CAAC,CAAC;IAC1C,OAAO;QACL,MAAM;QACN,UAAU,EAAE,CAAC,IAAwB,EAAE,EAAE,CAAC,IAAA,8BAAiB,EAAC,MAAM,EAAE,IAAI,CAAC;QACzE,MAAM,EAAE,CAAC,IAAwB,EAAE,EAAE,CACnC,CAAC,OAAY,EAAE,KAAU,EAAE,IAAS,EAAE,EAAE,CACtC,IAAA,0BAAa,EAAC,OAAO,EAAE,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,EAAE,IAAI,CAAC;QACrD,gBAAgB,EAAhB,6BAAgB;QAChB,oBAAoB,EAApB,iCAAoB;KACrB,CAAC;AACJ,CAAC;AAXD,0BAWC;AAED,iCAAiC;AACjC,yCAA4C;AAAnC,0GAAA,aAAa,OAAA;AAEtB,2CAAuG;AAA9F,8GAAA,gBAAgB,OAAA;AAAE,kHAAA,oBAAoB,OAAA;AAAE,8GAAA,gBAAgB,OAAA;AAAE,2GAAA,aAAa,OAAA;AAChF,sDAA4D;AAAnD,+GAAA,iBAAiB,OAAA;AAC1B,sDAAwD;AAA/C,2GAAA,aAAa,OAAA;AACtB,mDAA0D;AAAjD,8GAAA,iBAAiB,OAAA;AAC1B,6CAAoD;AAA3C,wGAAA,cAAc,OAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { StratumClient } from "../client.js";
|
|
2
|
+
import type { MiddlewareOptions } from "../types.js";
|
|
3
|
+
export declare function expressMiddleware(client: StratumClient, options?: MiddlewareOptions): (req: any, res: any, next: any) => Promise<void>;
|
|
4
|
+
//# sourceMappingURL=express.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAKrD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,iBAAiB,SAC/D,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAG,QAAQ,IAAI,CAAC,CAoD5D"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.expressMiddleware = void 0;
|
|
4
|
+
const core_1 = require("@stratum-hq/core");
|
|
5
|
+
const context_js_1 = require("../context.js");
|
|
6
|
+
const jwt_js_1 = require("../resolvers/jwt.js");
|
|
7
|
+
const header_js_1 = require("../resolvers/header.js");
|
|
8
|
+
function expressMiddleware(client, options) {
|
|
9
|
+
return async (req, res, next) => {
|
|
10
|
+
try {
|
|
11
|
+
// Resolve tenant ID: JWT → header → custom resolvers
|
|
12
|
+
let tenantId = null;
|
|
13
|
+
tenantId = (0, jwt_js_1.resolveFromJwt)(req, options?.jwtClaimPath, {
|
|
14
|
+
secret: options?.jwtSecret,
|
|
15
|
+
verify: options?.jwtVerify,
|
|
16
|
+
});
|
|
17
|
+
if (!tenantId) {
|
|
18
|
+
tenantId = (0, header_js_1.resolveFromHeader)(req);
|
|
19
|
+
}
|
|
20
|
+
if (!tenantId && options?.resolvers) {
|
|
21
|
+
for (const resolver of options.resolvers) {
|
|
22
|
+
const result = await resolver.resolve(req);
|
|
23
|
+
if (result) {
|
|
24
|
+
tenantId = result;
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (!tenantId) {
|
|
30
|
+
res.status(400).json({ error: { code: "MISSING_TENANT", message: "Tenant ID could not be resolved from request" } });
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
let context;
|
|
34
|
+
try {
|
|
35
|
+
context = await client.resolveTenant(tenantId);
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
if (err instanceof core_1.TenantNotFoundError) {
|
|
39
|
+
res.status(404).json({ error: { code: "TENANT_NOT_FOUND", message: `Tenant not found: ${tenantId}` } });
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
throw err;
|
|
43
|
+
}
|
|
44
|
+
req.tenant = context;
|
|
45
|
+
(0, context_js_1.runWithTenantContext)(context, () => {
|
|
46
|
+
next();
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
if (options?.onError && err instanceof Error) {
|
|
51
|
+
options.onError(err, req);
|
|
52
|
+
}
|
|
53
|
+
next(err);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
exports.expressMiddleware = expressMiddleware;
|
|
58
|
+
//# sourceMappingURL=express.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express.js","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":";;;AAAA,2CAAuD;AAGvD,8CAAqD;AACrD,gDAAqD;AACrD,sDAA2D;AAE3D,SAAgB,iBAAiB,CAAC,MAAqB,EAAE,OAA2B;IAClF,OAAO,KAAK,EAAE,GAAQ,EAAE,GAAQ,EAAE,IAAS,EAAiB,EAAE;QAC5D,IAAI,CAAC;YACH,qDAAqD;YACrD,IAAI,QAAQ,GAAkB,IAAI,CAAC;YAEnC,QAAQ,GAAG,IAAA,uBAAc,EAAC,GAAG,EAAE,OAAO,EAAE,YAAY,EAAE;gBACpD,MAAM,EAAE,OAAO,EAAE,SAAS;gBAC1B,MAAM,EAAE,OAAO,EAAE,SAAS;aAC3B,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,QAAQ,GAAG,IAAA,6BAAiB,EAAC,GAAG,CAAC,CAAC;YACpC,CAAC;YAED,IAAI,CAAC,QAAQ,IAAI,OAAO,EAAE,SAAS,EAAE,CAAC;gBACpC,KAAK,MAAM,QAAQ,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;oBACzC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;oBAC3C,IAAI,MAAM,EAAE,CAAC;wBACX,QAAQ,GAAG,MAAM,CAAC;wBAClB,MAAM;oBACR,CAAC;gBACH,CAAC;YACH,CAAC;YAED,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,8CAA8C,EAAE,EAAE,CAAC,CAAC;gBACrH,OAAO;YACT,CAAC;YAED,IAAI,OAAO,CAAC;YACZ,IAAI,CAAC;gBACH,OAAO,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YACjD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,0BAAmB,EAAE,CAAC;oBACvC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,qBAAqB,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;oBACxG,OAAO;gBACT,CAAC;gBACD,MAAM,GAAG,CAAC;YACZ,CAAC;YAED,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC;YAErB,IAAA,iCAAoB,EAAC,OAAO,EAAE,GAAG,EAAE;gBACjC,IAAI,EAAE,CAAC;YACT,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,OAAO,EAAE,OAAO,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;gBAC7C,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAC5B,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,CAAC;QACZ,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AArDD,8CAqDC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { StratumClient } from "../client.js";
|
|
2
|
+
import type { MiddlewareOptions } from "../types.js";
|
|
3
|
+
export declare function fastifyPlugin(fastify: any, options: {
|
|
4
|
+
client: StratumClient;
|
|
5
|
+
} & MiddlewareOptions, done: any): void;
|
|
6
|
+
//# sourceMappingURL=fastify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastify.d.ts","sourceRoot":"","sources":["../../src/middleware/fastify.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAKrD,wBAAgB,aAAa,CAC3B,OAAO,EAAE,GAAG,EACZ,OAAO,EAAE;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE,GAAG,iBAAiB,EACtD,IAAI,EAAE,GAAG,GACR,IAAI,CA0DN"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fastifyPlugin = void 0;
|
|
4
|
+
const core_1 = require("@stratum-hq/core");
|
|
5
|
+
const context_js_1 = require("../context.js");
|
|
6
|
+
const jwt_js_1 = require("../resolvers/jwt.js");
|
|
7
|
+
const header_js_1 = require("../resolvers/header.js");
|
|
8
|
+
function fastifyPlugin(fastify, options, done) {
|
|
9
|
+
const { client, ...middlewareOptions } = options;
|
|
10
|
+
fastify.decorateRequest("tenant", null);
|
|
11
|
+
fastify.addHook("onRequest", (request, reply, done) => {
|
|
12
|
+
// Resolve tenant ID: JWT → header → custom resolvers
|
|
13
|
+
let tenantId = null;
|
|
14
|
+
tenantId = (0, jwt_js_1.resolveFromJwt)(request, middlewareOptions.jwtClaimPath, {
|
|
15
|
+
secret: middlewareOptions.jwtSecret,
|
|
16
|
+
verify: middlewareOptions.jwtVerify,
|
|
17
|
+
});
|
|
18
|
+
if (!tenantId) {
|
|
19
|
+
tenantId = (0, header_js_1.resolveFromHeader)(request);
|
|
20
|
+
}
|
|
21
|
+
const resolveAndRun = async () => {
|
|
22
|
+
if (!tenantId && middlewareOptions.resolvers) {
|
|
23
|
+
for (const resolver of middlewareOptions.resolvers) {
|
|
24
|
+
const result = await resolver.resolve(request);
|
|
25
|
+
if (result) {
|
|
26
|
+
tenantId = result;
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (!tenantId) {
|
|
32
|
+
reply.status(400).send({ error: { code: "MISSING_TENANT", message: "Tenant ID could not be resolved from request" } });
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
let context;
|
|
36
|
+
try {
|
|
37
|
+
context = await client.resolveTenant(tenantId);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
if (err instanceof core_1.TenantNotFoundError) {
|
|
41
|
+
reply.status(404).send({ error: { code: "TENANT_NOT_FOUND", message: `Tenant not found: ${tenantId}` } });
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (middlewareOptions.onError && err instanceof Error) {
|
|
45
|
+
middlewareOptions.onError(err, request);
|
|
46
|
+
}
|
|
47
|
+
throw err;
|
|
48
|
+
}
|
|
49
|
+
request.tenant = context;
|
|
50
|
+
// Use run (not enterWith) to bind context only for this request's lifecycle
|
|
51
|
+
(0, context_js_1.runWithTenantContext)(context, done);
|
|
52
|
+
};
|
|
53
|
+
resolveAndRun().catch(done);
|
|
54
|
+
});
|
|
55
|
+
done();
|
|
56
|
+
}
|
|
57
|
+
exports.fastifyPlugin = fastifyPlugin;
|
|
58
|
+
//# sourceMappingURL=fastify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastify.js","sourceRoot":"","sources":["../../src/middleware/fastify.ts"],"names":[],"mappings":";;;AAAA,2CAAuD;AAIvD,8CAAqD;AACrD,gDAAqD;AACrD,sDAA2D;AAE3D,SAAgB,aAAa,CAC3B,OAAY,EACZ,OAAsD,EACtD,IAAS;IAET,MAAM,EAAE,MAAM,EAAE,GAAG,iBAAiB,EAAE,GAAG,OAAO,CAAC;IAEjD,OAAO,CAAC,eAAe,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAExC,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,OAAY,EAAE,KAAU,EAAE,IAAS,EAAE,EAAE;QACnE,qDAAqD;QACrD,IAAI,QAAQ,GAAkB,IAAI,CAAC;QAEnC,QAAQ,GAAG,IAAA,uBAAc,EAAC,OAAO,EAAE,iBAAiB,CAAC,YAAY,EAAE;YACjE,MAAM,EAAE,iBAAiB,CAAC,SAAS;YACnC,MAAM,EAAE,iBAAiB,CAAC,SAAS;SACpC,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,QAAQ,GAAG,IAAA,6BAAiB,EAAC,OAAO,CAAC,CAAC;QACxC,CAAC;QAED,MAAM,aAAa,GAAG,KAAK,IAAI,EAAE;YAC/B,IAAI,CAAC,QAAQ,IAAI,iBAAiB,CAAC,SAAS,EAAE,CAAC;gBAC7C,KAAK,MAAM,QAAQ,IAAI,iBAAiB,CAAC,SAAS,EAAE,CAAC;oBACnD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;oBAC/C,IAAI,MAAM,EAAE,CAAC;wBACX,QAAQ,GAAG,MAAM,CAAC;wBAClB,MAAM;oBACR,CAAC;gBACH,CAAC;YACH,CAAC;YAED,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,8CAA8C,EAAE,EAAE,CAAC,CAAC;gBACvH,OAAO;YACT,CAAC;YAED,IAAI,OAA4B,CAAC;YACjC,IAAI,CAAC;gBACH,OAAO,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YACjD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,0BAAmB,EAAE,CAAC;oBACvC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,qBAAqB,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;oBAC1G,OAAO;gBACT,CAAC;gBACD,IAAI,iBAAiB,CAAC,OAAO,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;oBACtD,iBAAiB,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;gBAC1C,CAAC;gBACD,MAAM,GAAG,CAAC;YACZ,CAAC;YAED,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC;YAEzB,4EAA4E;YAC5E,IAAA,iCAAoB,EAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACtC,CAAC,CAAC;QAEF,aAAa,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,IAAI,EAAE,CAAC;AACT,CAAC;AA9DD,sCA8DC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom.d.ts","sourceRoot":"","sources":["../../src/resolvers/custom.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC/D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom.js","sourceRoot":"","sources":["../../src/resolvers/custom.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"header.d.ts","sourceRoot":"","sources":["../../src/resolvers/header.ts"],"names":[],"mappings":"AAEA,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAO7D"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveFromHeader = void 0;
|
|
4
|
+
const core_1 = require("@stratum-hq/core");
|
|
5
|
+
function resolveFromHeader(req) {
|
|
6
|
+
const r = req;
|
|
7
|
+
const headers = r["headers"];
|
|
8
|
+
if (!headers)
|
|
9
|
+
return null;
|
|
10
|
+
const value = headers[core_1.TENANT_HEADER.toLowerCase()] ?? headers[core_1.TENANT_HEADER];
|
|
11
|
+
if (!value)
|
|
12
|
+
return null;
|
|
13
|
+
return Array.isArray(value) ? value[0] ?? null : value;
|
|
14
|
+
}
|
|
15
|
+
exports.resolveFromHeader = resolveFromHeader;
|
|
16
|
+
//# sourceMappingURL=header.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"header.js","sourceRoot":"","sources":["../../src/resolvers/header.ts"],"names":[],"mappings":";;;AAAA,2CAAiD;AAEjD,SAAgB,iBAAiB,CAAC,GAAY;IAC5C,MAAM,CAAC,GAAG,GAA8B,CAAC;IACzC,MAAM,OAAO,GAAG,CAAC,CAAC,SAAS,CAA8D,CAAC;IAC1F,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,MAAM,KAAK,GAAG,OAAO,CAAC,oBAAa,CAAC,WAAW,EAAE,CAAC,IAAI,OAAO,CAAC,oBAAa,CAAC,CAAC;IAC7E,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;AACzD,CAAC;AAPD,8CAOC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface JwtResolverOptions {
|
|
2
|
+
secret?: string;
|
|
3
|
+
verify?: (token: string) => Record<string, unknown> | null;
|
|
4
|
+
}
|
|
5
|
+
export declare function resolveFromJwt(req: unknown, claimPath?: string, options?: JwtResolverOptions): string | null;
|
|
6
|
+
//# sourceMappingURL=jwt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../src/resolvers/jwt.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC5D;AAcD,wBAAgB,cAAc,CAC5B,GAAG,EAAE,OAAO,EACZ,SAAS,GAAE,MAAoB,EAC/B,OAAO,CAAC,EAAE,kBAAkB,GAC3B,MAAM,GAAG,IAAI,CAuCf"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveFromJwt = void 0;
|
|
4
|
+
function verifyWithJsonwebtoken(token, secret) {
|
|
5
|
+
try {
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
7
|
+
const jwt = require("jsonwebtoken");
|
|
8
|
+
const decoded = jwt.verify(token, secret, { algorithms: ["HS256"] });
|
|
9
|
+
if (typeof decoded === "string")
|
|
10
|
+
return null;
|
|
11
|
+
return decoded;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function resolveFromJwt(req, claimPath = "tenant_id", options) {
|
|
18
|
+
const r = req;
|
|
19
|
+
const headers = r["headers"];
|
|
20
|
+
if (!headers)
|
|
21
|
+
return null;
|
|
22
|
+
const authHeader = headers["authorization"];
|
|
23
|
+
const auth = Array.isArray(authHeader) ? authHeader[0] : authHeader;
|
|
24
|
+
if (!auth || !auth.startsWith("Bearer "))
|
|
25
|
+
return null;
|
|
26
|
+
const token = auth.slice(7);
|
|
27
|
+
let claims = null;
|
|
28
|
+
if (options?.verify) {
|
|
29
|
+
// User-supplied verify function takes priority
|
|
30
|
+
claims = options.verify(token);
|
|
31
|
+
}
|
|
32
|
+
else if (options?.secret) {
|
|
33
|
+
// Try jsonwebtoken signature verification
|
|
34
|
+
claims = verifyWithJsonwebtoken(token, options.secret);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
// No secret or verify function provided — refuse to trust unsigned tokens
|
|
38
|
+
console.warn("[stratum] JWT ignored: no jwtSecret or jwtVerify provided. " +
|
|
39
|
+
"Configure middleware options to enable JWT tenant resolution.");
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
if (!claims)
|
|
43
|
+
return null;
|
|
44
|
+
// Support dotted claim paths like "stratum.tenant_id"
|
|
45
|
+
const segments = claimPath.split(".");
|
|
46
|
+
let current = claims;
|
|
47
|
+
for (const seg of segments) {
|
|
48
|
+
if (current == null || typeof current !== "object")
|
|
49
|
+
return null;
|
|
50
|
+
current = current[seg];
|
|
51
|
+
}
|
|
52
|
+
return typeof current === "string" ? current : null;
|
|
53
|
+
}
|
|
54
|
+
exports.resolveFromJwt = resolveFromJwt;
|
|
55
|
+
//# sourceMappingURL=jwt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../src/resolvers/jwt.ts"],"names":[],"mappings":";;;AAKA,SAAS,sBAAsB,CAAC,KAAa,EAAE,MAAc;IAC3D,IAAI,CAAC;QACH,iEAAiE;QACjE,MAAM,GAAG,GAAG,OAAO,CAAC,cAAc,CAAkC,CAAC;QACrE,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACrE,IAAI,OAAO,OAAO,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC7C,OAAO,OAAkC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAgB,cAAc,CAC5B,GAAY,EACZ,YAAoB,WAAW,EAC/B,OAA4B;IAE5B,MAAM,CAAC,GAAG,GAA8B,CAAC;IACzC,MAAM,OAAO,GAAG,CAAC,CAAC,SAAS,CAA8D,CAAC;IAC1F,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,MAAM,UAAU,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IACpE,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IAEtD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE5B,IAAI,MAAM,GAAmC,IAAI,CAAC;IAElD,IAAI,OAAO,EAAE,MAAM,EAAE,CAAC;QACpB,+CAA+C;QAC/C,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;SAAM,IAAI,OAAO,EAAE,MAAM,EAAE,CAAC;QAC3B,0CAA0C;QAC1C,MAAM,GAAG,sBAAsB,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACzD,CAAC;SAAM,CAAC;QACN,0EAA0E;QAC1E,OAAO,CAAC,IAAI,CACV,6DAA6D;YAC7D,+DAA+D,CAChE,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEzB,sDAAsD;IACtD,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,OAAO,GAAY,MAAM,CAAC;IAC9B,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,IAAI,OAAO,IAAI,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAChE,OAAO,GAAI,OAAmC,CAAC,GAAG,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACtD,CAAC;AA3CD,wCA2CC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { TenantContextLegacy, TenantNode, CreateTenantInput, UpdateTenantInput, MoveTenantInput, ResolvedPermission } from "@stratum-hq/core";
|
|
2
|
+
export type { TenantContextLegacy, TenantNode, CreateTenantInput, UpdateTenantInput, MoveTenantInput, ResolvedPermission };
|
|
3
|
+
export type { TenantResolver } from "./resolvers/custom.js";
|
|
4
|
+
export interface MiddlewareOptions {
|
|
5
|
+
resolvers?: import("./resolvers/custom.js").TenantResolver[];
|
|
6
|
+
headerName?: string;
|
|
7
|
+
jwtClaimPath?: string;
|
|
8
|
+
jwtSecret?: string;
|
|
9
|
+
jwtVerify?: (token: string) => Record<string, unknown> | null;
|
|
10
|
+
onError?: (err: Error, req: unknown) => void;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEnJ,YAAY,EAAE,mBAAmB,EAAE,UAAU,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,eAAe,EAAE,kBAAkB,EAAE,CAAC;AAE3H,YAAY,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,OAAO,uBAAuB,EAAE,cAAc,EAAE,CAAC;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC9D,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;CAC9C"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@stratum-hq/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Stratum Node.js SDK for multi-tenant context propagation",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"lint": "tsc --noEmit",
|
|
22
|
+
"clean": "rm -rf dist"
|
|
23
|
+
},
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public",
|
|
26
|
+
"registry": "https://registry.npmjs.org/"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@stratum-hq/core": "*",
|
|
30
|
+
"lru-cache": "^10.2.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/express": "^4.17.0",
|
|
34
|
+
"express": "^4.18.0",
|
|
35
|
+
"fastify": "^5.3.2",
|
|
36
|
+
"typescript": "^5.4.0",
|
|
37
|
+
"vitest": "^1.6.0"
|
|
38
|
+
}
|
|
39
|
+
}
|