@classytic/arc 2.10.8 → 2.11.1
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/{BaseController-DVNKvoX4.mjs → BaseController-JNV08qOT.mjs} +480 -442
- package/dist/{queryCachePlugin-Dumka73q.d.mts → QueryCache-DOBNHBE0.d.mts} +2 -32
- package/dist/adapters/index.d.mts +2 -2
- package/dist/adapters/index.mjs +1 -1
- package/dist/{adapters-BXY4i-hw.mjs → adapters-D0tT2Tyo.mjs} +54 -0
- package/dist/audit/index.d.mts +1 -1
- package/dist/auth/index.d.mts +1 -1
- package/dist/auth/index.mjs +5 -5
- package/dist/{betterAuthOpenApi--rdY15Ld.mjs → betterAuthOpenApi-DwxtK3uG.mjs} +1 -1
- package/dist/cache/index.d.mts +3 -2
- package/dist/cache/index.mjs +3 -3
- package/dist/cli/commands/docs.mjs +2 -2
- package/dist/cli/commands/generate.mjs +37 -27
- package/dist/cli/commands/init.mjs +46 -33
- package/dist/cli/commands/introspect.mjs +1 -1
- package/dist/context/index.mjs +1 -1
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +4 -3
- package/dist/core-DXdSSFW-.mjs +1037 -0
- package/dist/createActionRouter-BwaSM0No.mjs +166 -0
- package/dist/{createApp-BwnEAO2h.mjs → createApp-P1d6rjPy.mjs} +75 -27
- package/dist/docs/index.d.mts +1 -1
- package/dist/docs/index.mjs +2 -2
- package/dist/{elevation-Dci0AYLT.mjs → elevation-DOFoxoDs.mjs} +1 -1
- package/dist/{errorHandler-CSxe7KIM.mjs → errorHandler-BQm8ZxTK.mjs} +1 -1
- package/dist/{eventPlugin-ByU4Cv0e.mjs → eventPlugin--5HIkdPU.mjs} +1 -1
- package/dist/events/index.d.mts +3 -3
- package/dist/events/index.mjs +2 -2
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/factory/index.d.mts +2 -2
- package/dist/factory/index.mjs +2 -2
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.mjs +1 -1
- package/dist/idempotency/index.d.mts +3 -3
- package/dist/idempotency/index.mjs +1 -1
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/{index-C_Noptz-.d.mts → index-BYCqHCVu.d.mts} +2 -2
- package/dist/{index-BGbpGVyM.d.mts → index-C_bgx9o4.d.mts} +712 -500
- package/dist/{index-BziRPS4H.d.mts → index-CvM1e09j.d.mts} +29 -10
- package/dist/{index-EqQN6p0W.d.mts → index-pUczGjO0.d.mts} +11 -8
- package/dist/index-smCAoA5W.d.mts +1179 -0
- package/dist/index.d.mts +6 -38
- package/dist/index.mjs +9 -9
- package/dist/integrations/event-gateway.d.mts +1 -1
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +2 -2
- package/dist/integrations/mcp/index.d.mts +2 -2
- package/dist/integrations/mcp/index.mjs +1 -1
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/integrations/streamline.d.mts +46 -5
- package/dist/integrations/streamline.mjs +50 -21
- package/dist/integrations/websocket-redis.d.mts +1 -1
- package/dist/integrations/websocket.d.mts +2 -154
- package/dist/integrations/websocket.mjs +292 -224
- package/dist/{keys-nWQGUTu1.mjs → keys-CARyUjiR.mjs} +2 -0
- package/dist/{loadResources-Bksk8ydA.mjs → loadResources-CPpkyKfM.mjs} +32 -8
- package/dist/middleware/index.d.mts +1 -1
- package/dist/middleware/index.mjs +1 -1
- package/dist/{openapi-DpNpqBmo.mjs → openapi-C0L9ar7m.mjs} +4 -4
- package/dist/org/index.d.mts +1 -1
- package/dist/permissions/index.d.mts +1 -1
- package/dist/permissions/index.mjs +2 -4
- package/dist/{permissions-wkqRwicB.mjs → permissions-B4vU9L0Q.mjs} +221 -3
- package/dist/{pipe-CGJxqDGx.mjs → pipe-DVoIheVC.mjs} +1 -1
- package/dist/pipeline/index.d.mts +1 -1
- package/dist/pipeline/index.mjs +1 -1
- package/dist/plugins/index.d.mts +4 -4
- package/dist/plugins/index.mjs +10 -10
- package/dist/plugins/response-cache.mjs +1 -1
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +42 -24
- package/dist/presets/filesUpload.d.mts +1 -1
- package/dist/presets/filesUpload.mjs +3 -3
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/index.mjs +1 -1
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/multiTenant.mjs +6 -0
- package/dist/presets/search.d.mts +1 -1
- package/dist/presets/search.mjs +1 -1
- package/dist/{presets-CrwOvuXI.mjs → presets-k604Lj99.mjs} +1 -1
- package/dist/queryCachePlugin-BUXBSm4F.d.mts +34 -0
- package/dist/{queryCachePlugin-ChLNZvFT.mjs → queryCachePlugin-Bq6bO6vc.mjs} +3 -3
- package/dist/{redis-MXLp1oOf.d.mts → redis-Cm1gnRDf.d.mts} +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +2 -2
- package/dist/{resourceToTools-BhF3JV5p.mjs → resourceToTools--okX6QBr.mjs} +534 -420
- package/dist/routerShared-DeESFp4a.mjs +515 -0
- package/dist/schemaIR-BlG9bY7v.mjs +137 -0
- package/dist/scope/index.mjs +2 -2
- package/dist/testing/index.d.mts +367 -711
- package/dist/testing/index.mjs +637 -1434
- package/dist/{tracing-xqXzWeaf.d.mts → tracing-DokiEsuz.d.mts} +9 -4
- package/dist/types/index.d.mts +3 -3
- package/dist/types/index.mjs +1 -3
- package/dist/{types-CVdgPXBW.d.mts → types-BdA4uMBV.d.mts} +191 -28
- package/dist/{types-CVKBssX5.d.mts → types-Bh_gEJBi.d.mts} +1 -1
- package/dist/utils/index.d.mts +2 -968
- package/dist/utils/index.mjs +5 -6
- package/dist/utils-D3Yxnrwr.mjs +1639 -0
- package/dist/websocket-CyJ1VIFI.d.mts +186 -0
- package/package.json +7 -5
- package/skills/arc/SKILL.md +124 -39
- package/skills/arc/references/testing.md +212 -183
- package/dist/applyPermissionResult-QhV1Pa-g.mjs +0 -37
- package/dist/core-3MWJosCH.mjs +0 -1459
- package/dist/createActionRouter-C8UUB3Px.mjs +0 -249
- package/dist/errors-BI8kEKsO.d.mts +0 -140
- package/dist/fields-CTMWOUDt.mjs +0 -126
- package/dist/queryParser-NR__Qiju.mjs +0 -419
- package/dist/types-CDnTEpga.mjs +0 -27
- package/dist/utils-LMwVidKy.mjs +0 -947
- /package/dist/{HookSystem-BjFu7zf1.mjs → HookSystem-CGsMd6oK.mjs} +0 -0
- /package/dist/{ResourceRegistry-CcN2LVrc.mjs → ResourceRegistry-DkAeAuTX.mjs} +0 -0
- /package/dist/{actionPermissions-TUVR3uiZ.mjs → actionPermissions-C8YYU92K.mjs} +0 -0
- /package/dist/{caching-3h93rkJM.mjs → caching-CheW3m-S.mjs} +0 -0
- /package/dist/{errorHandler-2ii4RIYr.d.mts → errorHandler-Co3lnVmJ.d.mts} +0 -0
- /package/dist/{errors-BqdUDja_.mjs → errors-D5c-5BJL.mjs} +0 -0
- /package/dist/{eventPlugin-D1ThQ1Pp.d.mts → eventPlugin-CUNjYYRY.d.mts} +0 -0
- /package/dist/{interface-B-pe8fhj.d.mts → interface-CkkWm5uR.d.mts} +0 -0
- /package/dist/{interface-yhyb_pLY.d.mts → interface-Da0r7Lna.d.mts} +0 -0
- /package/dist/{memory-DqI-449b.mjs → memory-DikHSvWa.mjs} +0 -0
- /package/dist/{metrics-TuOmguhi.mjs → metrics-Csh4nsvv.mjs} +0 -0
- /package/dist/{multipartBody-CUQGVlM_.mjs → multipartBody-CvTR1Un6.mjs} +0 -0
- /package/dist/{pluralize-CWP6MB39.mjs → pluralize-BneOJkpi.mjs} +0 -0
- /package/dist/{redis-stream-bkO88VHx.d.mts → redis-stream-CM8TXTix.d.mts} +0 -0
- /package/dist/{registry-B0Wl7uVV.mjs → registry-D63ee7fl.mjs} +0 -0
- /package/dist/{replyHelpers-BLojtuvR.mjs → replyHelpers-ByllIXXV.mjs} +0 -0
- /package/dist/{requestContext-C38GskNt.mjs → requestContext-CfRkaxwf.mjs} +0 -0
- /package/dist/{schemaConverter-BxFDdtXu.mjs → schemaConverter-B0oKLuqI.mjs} +0 -0
- /package/dist/{sse-D8UeDwis.mjs → sse-V7aXc3bW.mjs} +0 -0
- /package/dist/{store-helpers-DYYUQbQN.mjs → store-helpers-BhrzxvyQ.mjs} +0 -0
- /package/dist/{typeGuards-Cj5Rgvlg.mjs → typeGuards-CcFZXgU7.mjs} +0 -0
- /package/dist/{types-D57iXYb8.mjs → types-DV9WDfeg.mjs} +0 -0
- /package/dist/{versioning-B6mimogM.mjs → versioning-CGPjkqAg.mjs} +0 -0
- /package/dist/{versioning-CeUXHfjw.d.mts → versioning-M9lNLhO8.d.mts} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import fp from "fastify-plugin";
|
|
2
|
-
//#region src/integrations/websocket.ts
|
|
2
|
+
//#region src/integrations/websocket/adapter.ts
|
|
3
3
|
/**
|
|
4
4
|
* Default adapter — no cross-instance broadcast (single-instance only).
|
|
5
5
|
* All methods are no-ops. Used when no adapter is configured.
|
|
@@ -10,6 +10,271 @@ var LocalWebSocketAdapter = class {
|
|
|
10
10
|
async subscribe() {}
|
|
11
11
|
async close() {}
|
|
12
12
|
};
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/integrations/websocket/auth.ts
|
|
15
|
+
function createCaptureReply() {
|
|
16
|
+
let rejected = false;
|
|
17
|
+
let capturedStatus;
|
|
18
|
+
const reply = {
|
|
19
|
+
code(statusCode) {
|
|
20
|
+
rejected = true;
|
|
21
|
+
capturedStatus = statusCode;
|
|
22
|
+
return reply;
|
|
23
|
+
},
|
|
24
|
+
send() {
|
|
25
|
+
return reply;
|
|
26
|
+
},
|
|
27
|
+
get rejected() {
|
|
28
|
+
return rejected;
|
|
29
|
+
},
|
|
30
|
+
get statusCode() {
|
|
31
|
+
return capturedStatus;
|
|
32
|
+
},
|
|
33
|
+
sent: false
|
|
34
|
+
};
|
|
35
|
+
return reply;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Run authentication against a request and return a uniform `AuthResult`
|
|
39
|
+
* (or `null` if denied). Handles both modes:
|
|
40
|
+
*
|
|
41
|
+
* - `customAuth` provided → call it directly; trust its return shape.
|
|
42
|
+
* - Otherwise → invoke `fastify.authenticate(request, captureReply)` to
|
|
43
|
+
* populate `request.user` / `request.scope`, then read IDs off those.
|
|
44
|
+
*
|
|
45
|
+
* This is the single source of truth for "did this request authenticate
|
|
46
|
+
* successfully, and what identity did it establish". The handshake path
|
|
47
|
+
* calls it once; the re-auth loop calls it on every interval.
|
|
48
|
+
*/
|
|
49
|
+
async function authenticateWebSocket(fastify, request, customAuth) {
|
|
50
|
+
if (customAuth) try {
|
|
51
|
+
return await customAuth(request);
|
|
52
|
+
} catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
const authenticate = fastify.authenticate;
|
|
56
|
+
if (!authenticate) return null;
|
|
57
|
+
const reply = createCaptureReply();
|
|
58
|
+
try {
|
|
59
|
+
await authenticate(request, reply);
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
if (reply.rejected) return null;
|
|
64
|
+
const shape = request;
|
|
65
|
+
const user = shape.user;
|
|
66
|
+
const scope = shape.scope;
|
|
67
|
+
if (!user) return null;
|
|
68
|
+
const userId = readIdField(user, "id") ?? readIdField(user, "sub");
|
|
69
|
+
const organizationId = scope ? readIdField(scope, "organizationId") : void 0;
|
|
70
|
+
return {
|
|
71
|
+
...userId !== void 0 ? { userId } : {},
|
|
72
|
+
...organizationId !== void 0 ? { organizationId } : {}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function readIdField(obj, key) {
|
|
76
|
+
const value = obj[key];
|
|
77
|
+
return typeof value === "string" ? value : void 0;
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
//#region src/integrations/websocket/connection.ts
|
|
81
|
+
async function handleConnection(ctx, socket, request) {
|
|
82
|
+
const { fastify, rooms, options } = ctx;
|
|
83
|
+
const clientId = ctx.nextClientId();
|
|
84
|
+
let userId;
|
|
85
|
+
let organizationId;
|
|
86
|
+
let serviceClientId;
|
|
87
|
+
let serviceScopes;
|
|
88
|
+
if (options.auth) {
|
|
89
|
+
const result = await authenticateWebSocket(fastify, request, options.authenticate);
|
|
90
|
+
if (!result) {
|
|
91
|
+
socket.close(4001, "Unauthorized");
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
userId = result.userId;
|
|
95
|
+
organizationId = result.organizationId;
|
|
96
|
+
serviceClientId = result.clientId;
|
|
97
|
+
serviceScopes = result.scopes;
|
|
98
|
+
}
|
|
99
|
+
const client = {
|
|
100
|
+
id: clientId,
|
|
101
|
+
socket,
|
|
102
|
+
subscriptions: /* @__PURE__ */ new Set(),
|
|
103
|
+
userId,
|
|
104
|
+
organizationId,
|
|
105
|
+
...serviceClientId ? { clientId: serviceClientId } : {},
|
|
106
|
+
...serviceScopes ? { scopes: serviceScopes } : {}
|
|
107
|
+
};
|
|
108
|
+
rooms.addClient(client);
|
|
109
|
+
await options.onConnect?.(client);
|
|
110
|
+
socket.send(JSON.stringify({
|
|
111
|
+
type: "connected",
|
|
112
|
+
clientId,
|
|
113
|
+
resources: options.resources
|
|
114
|
+
}));
|
|
115
|
+
let heartbeatTimer;
|
|
116
|
+
if (options.heartbeatInterval > 0) heartbeatTimer = setInterval(() => {
|
|
117
|
+
if (socket.readyState === 1) socket.send(JSON.stringify({
|
|
118
|
+
type: "ping",
|
|
119
|
+
timestamp: Date.now()
|
|
120
|
+
}));
|
|
121
|
+
}, options.heartbeatInterval);
|
|
122
|
+
let reauthTimer;
|
|
123
|
+
if (options.reauthInterval > 0 && options.auth) reauthTimer = setInterval(async () => {
|
|
124
|
+
if (socket.readyState !== 1) return;
|
|
125
|
+
if (!await authenticateWebSocket(fastify, request, options.authenticate)) {
|
|
126
|
+
socket.send(JSON.stringify({
|
|
127
|
+
type: "error",
|
|
128
|
+
error: "Session expired"
|
|
129
|
+
}));
|
|
130
|
+
socket.close(4003, "Session expired");
|
|
131
|
+
}
|
|
132
|
+
}, options.reauthInterval);
|
|
133
|
+
socket.on("message", async (raw) => {
|
|
134
|
+
if ((typeof raw === "string" ? Buffer.byteLength(raw) : raw.length) > options.maxMessageBytes) {
|
|
135
|
+
socket.send(JSON.stringify({
|
|
136
|
+
type: "error",
|
|
137
|
+
error: "Message too large"
|
|
138
|
+
}));
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
let msg;
|
|
142
|
+
try {
|
|
143
|
+
msg = JSON.parse(typeof raw === "string" ? raw : raw.toString());
|
|
144
|
+
} catch {
|
|
145
|
+
socket.send(JSON.stringify({
|
|
146
|
+
type: "error",
|
|
147
|
+
error: "Invalid message format"
|
|
148
|
+
}));
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
switch (msg.type) {
|
|
152
|
+
case "subscribe": {
|
|
153
|
+
const room = msg.resource ?? msg.channel;
|
|
154
|
+
if (!room) break;
|
|
155
|
+
if (client.subscriptions.size >= options.maxSubscriptionsPerClient) {
|
|
156
|
+
socket.send(JSON.stringify({
|
|
157
|
+
type: "error",
|
|
158
|
+
channel: room,
|
|
159
|
+
error: "Subscription limit reached"
|
|
160
|
+
}));
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
if (options.roomPolicy) {
|
|
164
|
+
if (!await options.roomPolicy(client, room)) {
|
|
165
|
+
socket.send(JSON.stringify({
|
|
166
|
+
type: "error",
|
|
167
|
+
channel: room,
|
|
168
|
+
error: "Subscription denied"
|
|
169
|
+
}));
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const ok = rooms.subscribe(clientId, room);
|
|
174
|
+
socket.send(JSON.stringify({
|
|
175
|
+
type: ok ? "subscribed" : "error",
|
|
176
|
+
channel: room,
|
|
177
|
+
...ok ? {} : { error: "Room at capacity" }
|
|
178
|
+
}));
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
case "unsubscribe": {
|
|
182
|
+
const room = msg.resource ?? msg.channel;
|
|
183
|
+
if (room) {
|
|
184
|
+
rooms.unsubscribe(clientId, room);
|
|
185
|
+
socket.send(JSON.stringify({
|
|
186
|
+
type: "unsubscribed",
|
|
187
|
+
channel: room
|
|
188
|
+
}));
|
|
189
|
+
}
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
case "pong": break;
|
|
193
|
+
default:
|
|
194
|
+
await options.onMessage?.(client, msg);
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
socket.on("close", async () => {
|
|
199
|
+
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
200
|
+
if (reauthTimer) clearInterval(reauthTimer);
|
|
201
|
+
await options.onDisconnect?.(client);
|
|
202
|
+
rooms.removeClient(clientId);
|
|
203
|
+
});
|
|
204
|
+
socket.on("error", () => {
|
|
205
|
+
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
206
|
+
if (reauthTimer) clearInterval(reauthTimer);
|
|
207
|
+
rooms.removeClient(clientId);
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
//#endregion
|
|
211
|
+
//#region src/integrations/websocket/event-bridge.ts
|
|
212
|
+
/**
|
|
213
|
+
* Subscribe to `<resource>.created|updated|deleted` events for every
|
|
214
|
+
* resource in `resources` and fan them out to the matching room (same
|
|
215
|
+
* name as the resource). Returns the unsubscriber list so the caller can
|
|
216
|
+
* clean up on `onClose`.
|
|
217
|
+
*
|
|
218
|
+
* Org-scoped events (events carrying `meta.organizationId`) broadcast
|
|
219
|
+
* only to clients in that org; unscoped events broadcast to every
|
|
220
|
+
* subscriber of the room.
|
|
221
|
+
*/
|
|
222
|
+
async function wireResourceEvents(fastify, rooms, resources) {
|
|
223
|
+
const unsubscribers = [];
|
|
224
|
+
const events = fastify.events;
|
|
225
|
+
if (!events?.subscribe) return unsubscribers;
|
|
226
|
+
if (resources.length === 0) return unsubscribers;
|
|
227
|
+
const subscribe = events.subscribe;
|
|
228
|
+
for (const resourceName of resources) for (const op of [
|
|
229
|
+
"created",
|
|
230
|
+
"updated",
|
|
231
|
+
"deleted"
|
|
232
|
+
]) {
|
|
233
|
+
const unsub = await subscribe(`${resourceName}.${op}`, (event) => {
|
|
234
|
+
const room = resourceName;
|
|
235
|
+
const payload = JSON.stringify({
|
|
236
|
+
type: `${resourceName}.${op}`,
|
|
237
|
+
data: event.payload,
|
|
238
|
+
meta: {
|
|
239
|
+
timestamp: event.meta?.timestamp,
|
|
240
|
+
userId: event.meta?.userId,
|
|
241
|
+
organizationId: event.meta?.organizationId
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
if (event.meta?.organizationId) rooms.broadcastToOrgWithAdapter(event.meta.organizationId, room, payload);
|
|
245
|
+
else rooms.broadcastWithAdapter(room, payload);
|
|
246
|
+
});
|
|
247
|
+
unsubscribers.push(unsub);
|
|
248
|
+
}
|
|
249
|
+
return unsubscribers;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Register the optional `{path}/stats` endpoint.
|
|
253
|
+
*
|
|
254
|
+
* - `false` (default): no registration
|
|
255
|
+
* - `true`: open endpoint
|
|
256
|
+
* - `'authenticated'`: guarded by `fastify.authenticate` if registered;
|
|
257
|
+
* silently skipped with a warn when it isn't (doesn't fail boot — the
|
|
258
|
+
* stats endpoint is diagnostic, not load-bearing)
|
|
259
|
+
*/
|
|
260
|
+
function registerStatsRoute(fastify, rooms, path, expose) {
|
|
261
|
+
if (expose === true) {
|
|
262
|
+
fastify.get(`${path}/stats`, async () => ({
|
|
263
|
+
success: true,
|
|
264
|
+
data: rooms.getStats()
|
|
265
|
+
}));
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
if (expose === "authenticated") if (fastify.hasDecorator("authenticate")) {
|
|
269
|
+
const authenticate = fastify.authenticate;
|
|
270
|
+
fastify.get(`${path}/stats`, { preHandler: authenticate }, async () => ({
|
|
271
|
+
success: true,
|
|
272
|
+
data: rooms.getStats()
|
|
273
|
+
}));
|
|
274
|
+
} else fastify.log.warn("arc-websocket: exposeStats is \"authenticated\" but fastify.authenticate is not registered — stats endpoint skipped");
|
|
275
|
+
}
|
|
276
|
+
//#endregion
|
|
277
|
+
//#region src/integrations/websocket/room-manager.ts
|
|
13
278
|
var RoomManager = class {
|
|
14
279
|
rooms = /* @__PURE__ */ new Map();
|
|
15
280
|
clients = /* @__PURE__ */ new Map();
|
|
@@ -106,11 +371,12 @@ var RoomManager = class {
|
|
|
106
371
|
};
|
|
107
372
|
}
|
|
108
373
|
};
|
|
374
|
+
//#endregion
|
|
375
|
+
//#region src/integrations/websocket/plugin.ts
|
|
109
376
|
const websocketPluginImpl = async (fastify, options) => {
|
|
110
|
-
let clientCounter = 0;
|
|
111
377
|
const { path = "/ws", auth = true, resources = [], heartbeatInterval = 3e4, authenticate: customAuth, maxClientsPerRoom = 1e4, roomPolicy, maxMessageBytes = 16384, maxSubscriptionsPerClient = 100, reauthInterval = 0, adapter, exposeStats = false, onMessage, onConnect, onDisconnect } = options;
|
|
112
378
|
if (auth && !customAuth && !fastify.hasDecorator("authenticate")) throw new Error("[arc-websocket] auth is true but fastify.authenticate is not registered. Register an auth plugin before WebSocket, provide a custom authenticate function, or set auth: false.");
|
|
113
|
-
const rooms = new RoomManager(maxClientsPerRoom, adapter);
|
|
379
|
+
const rooms = new RoomManager(maxClientsPerRoom, adapter ?? new LocalWebSocketAdapter());
|
|
114
380
|
if (adapter) await adapter.subscribe((room, message) => {
|
|
115
381
|
if (room.startsWith("org:")) {
|
|
116
382
|
const parts = room.split(":");
|
|
@@ -139,229 +405,31 @@ const websocketPluginImpl = async (fastify, options) => {
|
|
|
139
405
|
},
|
|
140
406
|
getStats: () => rooms.getStats()
|
|
141
407
|
});
|
|
142
|
-
const eventUnsubscribers =
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
});
|
|
162
|
-
eventUnsubscribers.push(unsub);
|
|
163
|
-
}
|
|
164
|
-
fastify.get(path, { websocket: true }, async (socket, request) => {
|
|
165
|
-
const clientId = `ws_${++clientCounter}_${Date.now()}`;
|
|
166
|
-
let userId;
|
|
167
|
-
let organizationId;
|
|
168
|
-
let serviceClientId;
|
|
169
|
-
let serviceScopes;
|
|
170
|
-
if (auth) if (customAuth) {
|
|
171
|
-
const result = await customAuth(request);
|
|
172
|
-
if (!result) {
|
|
173
|
-
socket.close(4001, "Unauthorized");
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
userId = result.userId;
|
|
177
|
-
organizationId = result.organizationId;
|
|
178
|
-
serviceClientId = result.clientId;
|
|
179
|
-
serviceScopes = result.scopes;
|
|
180
|
-
} else {
|
|
181
|
-
if (fastify.authenticate) try {
|
|
182
|
-
let rejected = false;
|
|
183
|
-
const fakeReply = {
|
|
184
|
-
code(_statusCode) {
|
|
185
|
-
rejected = true;
|
|
186
|
-
return fakeReply;
|
|
187
|
-
},
|
|
188
|
-
send() {
|
|
189
|
-
return fakeReply;
|
|
190
|
-
},
|
|
191
|
-
sent: false
|
|
192
|
-
};
|
|
193
|
-
await fastify.authenticate(request, fakeReply);
|
|
194
|
-
if (rejected) {
|
|
195
|
-
socket.close(4001, "Unauthorized");
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
} catch {
|
|
199
|
-
socket.close(4001, "Unauthorized");
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
if (request.user) {
|
|
203
|
-
userId = request.user.id ?? request.user.sub;
|
|
204
|
-
organizationId = request.scope?.organizationId;
|
|
205
|
-
} else {
|
|
206
|
-
socket.close(4001, "Unauthorized");
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
408
|
+
const eventUnsubscribers = await wireResourceEvents(fastify, rooms, resources);
|
|
409
|
+
let clientCounter = 0;
|
|
410
|
+
const ctx = {
|
|
411
|
+
fastify,
|
|
412
|
+
rooms,
|
|
413
|
+
nextClientId: () => `ws_${++clientCounter}_${Date.now()}`,
|
|
414
|
+
options: {
|
|
415
|
+
auth,
|
|
416
|
+
resources,
|
|
417
|
+
heartbeatInterval,
|
|
418
|
+
maxClientsPerRoom,
|
|
419
|
+
maxMessageBytes,
|
|
420
|
+
maxSubscriptionsPerClient,
|
|
421
|
+
reauthInterval,
|
|
422
|
+
authenticate: customAuth,
|
|
423
|
+
roomPolicy,
|
|
424
|
+
onConnect,
|
|
425
|
+
onDisconnect,
|
|
426
|
+
onMessage
|
|
209
427
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
subscriptions: /* @__PURE__ */ new Set(),
|
|
214
|
-
userId,
|
|
215
|
-
organizationId,
|
|
216
|
-
...serviceClientId ? { clientId: serviceClientId } : {},
|
|
217
|
-
...serviceScopes ? { scopes: serviceScopes } : {}
|
|
218
|
-
};
|
|
219
|
-
rooms.addClient(client);
|
|
220
|
-
await onConnect?.(client);
|
|
221
|
-
socket.send(JSON.stringify({
|
|
222
|
-
type: "connected",
|
|
223
|
-
clientId,
|
|
224
|
-
resources
|
|
225
|
-
}));
|
|
226
|
-
let heartbeatTimer;
|
|
227
|
-
if (heartbeatInterval > 0) heartbeatTimer = setInterval(() => {
|
|
228
|
-
if (socket.readyState === 1) socket.send(JSON.stringify({
|
|
229
|
-
type: "ping",
|
|
230
|
-
timestamp: Date.now()
|
|
231
|
-
}));
|
|
232
|
-
}, heartbeatInterval);
|
|
233
|
-
let reauthTimer;
|
|
234
|
-
if (reauthInterval > 0 && auth) reauthTimer = setInterval(async () => {
|
|
235
|
-
if (socket.readyState !== 1) return;
|
|
236
|
-
try {
|
|
237
|
-
if (customAuth) {
|
|
238
|
-
if (!await customAuth(request)) {
|
|
239
|
-
socket.send(JSON.stringify({
|
|
240
|
-
type: "error",
|
|
241
|
-
error: "Session expired"
|
|
242
|
-
}));
|
|
243
|
-
socket.close(4003, "Session expired");
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
} else if (fastify.authenticate) {
|
|
247
|
-
let rejected = false;
|
|
248
|
-
const fakeReply = {
|
|
249
|
-
code() {
|
|
250
|
-
rejected = true;
|
|
251
|
-
return fakeReply;
|
|
252
|
-
},
|
|
253
|
-
send() {
|
|
254
|
-
return fakeReply;
|
|
255
|
-
},
|
|
256
|
-
sent: false
|
|
257
|
-
};
|
|
258
|
-
await fastify.authenticate(request, fakeReply);
|
|
259
|
-
if (rejected) {
|
|
260
|
-
socket.send(JSON.stringify({
|
|
261
|
-
type: "error",
|
|
262
|
-
error: "Session expired"
|
|
263
|
-
}));
|
|
264
|
-
socket.close(4003, "Session expired");
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
} catch {
|
|
269
|
-
socket.send(JSON.stringify({
|
|
270
|
-
type: "error",
|
|
271
|
-
error: "Session expired"
|
|
272
|
-
}));
|
|
273
|
-
socket.close(4003, "Session expired");
|
|
274
|
-
}
|
|
275
|
-
}, reauthInterval);
|
|
276
|
-
socket.on("message", async (raw) => {
|
|
277
|
-
if ((typeof raw === "string" ? Buffer.byteLength(raw) : raw.length) > maxMessageBytes) {
|
|
278
|
-
socket.send(JSON.stringify({
|
|
279
|
-
type: "error",
|
|
280
|
-
error: "Message too large"
|
|
281
|
-
}));
|
|
282
|
-
return;
|
|
283
|
-
}
|
|
284
|
-
try {
|
|
285
|
-
const msg = JSON.parse(typeof raw === "string" ? raw : raw.toString());
|
|
286
|
-
switch (msg.type) {
|
|
287
|
-
case "subscribe": {
|
|
288
|
-
const room = msg.resource ?? msg.channel;
|
|
289
|
-
if (room) {
|
|
290
|
-
if (client.subscriptions.size >= maxSubscriptionsPerClient) {
|
|
291
|
-
socket.send(JSON.stringify({
|
|
292
|
-
type: "error",
|
|
293
|
-
channel: room,
|
|
294
|
-
error: "Subscription limit reached"
|
|
295
|
-
}));
|
|
296
|
-
break;
|
|
297
|
-
}
|
|
298
|
-
if (roomPolicy) {
|
|
299
|
-
if (!await roomPolicy(client, room)) {
|
|
300
|
-
socket.send(JSON.stringify({
|
|
301
|
-
type: "error",
|
|
302
|
-
channel: room,
|
|
303
|
-
error: "Subscription denied"
|
|
304
|
-
}));
|
|
305
|
-
break;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
const ok = rooms.subscribe(clientId, room);
|
|
309
|
-
socket.send(JSON.stringify({
|
|
310
|
-
type: ok ? "subscribed" : "error",
|
|
311
|
-
channel: room,
|
|
312
|
-
...ok ? {} : { error: "Room at capacity" }
|
|
313
|
-
}));
|
|
314
|
-
}
|
|
315
|
-
break;
|
|
316
|
-
}
|
|
317
|
-
case "unsubscribe": {
|
|
318
|
-
const room = msg.resource ?? msg.channel;
|
|
319
|
-
if (room) {
|
|
320
|
-
rooms.unsubscribe(clientId, room);
|
|
321
|
-
socket.send(JSON.stringify({
|
|
322
|
-
type: "unsubscribed",
|
|
323
|
-
channel: room
|
|
324
|
-
}));
|
|
325
|
-
}
|
|
326
|
-
break;
|
|
327
|
-
}
|
|
328
|
-
case "pong": break;
|
|
329
|
-
default:
|
|
330
|
-
await onMessage?.(client, msg);
|
|
331
|
-
break;
|
|
332
|
-
}
|
|
333
|
-
} catch {
|
|
334
|
-
socket.send(JSON.stringify({
|
|
335
|
-
type: "error",
|
|
336
|
-
error: "Invalid message format"
|
|
337
|
-
}));
|
|
338
|
-
}
|
|
339
|
-
});
|
|
340
|
-
socket.on("close", async () => {
|
|
341
|
-
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
342
|
-
if (reauthTimer) clearInterval(reauthTimer);
|
|
343
|
-
await onDisconnect?.(client);
|
|
344
|
-
rooms.removeClient(clientId);
|
|
345
|
-
});
|
|
346
|
-
socket.on("error", () => {
|
|
347
|
-
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
348
|
-
if (reauthTimer) clearInterval(reauthTimer);
|
|
349
|
-
rooms.removeClient(clientId);
|
|
350
|
-
});
|
|
351
|
-
});
|
|
352
|
-
if (exposeStats === true) fastify.get(`${path}/stats`, async () => {
|
|
353
|
-
return {
|
|
354
|
-
success: true,
|
|
355
|
-
data: rooms.getStats()
|
|
356
|
-
};
|
|
357
|
-
});
|
|
358
|
-
else if (exposeStats === "authenticated") if (fastify.hasDecorator("authenticate")) fastify.get(`${path}/stats`, { preHandler: fastify.authenticate }, async () => {
|
|
359
|
-
return {
|
|
360
|
-
success: true,
|
|
361
|
-
data: rooms.getStats()
|
|
362
|
-
};
|
|
428
|
+
};
|
|
429
|
+
fastify.get(path, { websocket: true }, async (socket, request) => {
|
|
430
|
+
await handleConnection(ctx, socket, request);
|
|
363
431
|
});
|
|
364
|
-
|
|
432
|
+
registerStatsRoute(fastify, rooms, path, exposeStats);
|
|
365
433
|
fastify.addHook("onClose", async () => {
|
|
366
434
|
for (const unsub of eventUnsubscribers) unsub();
|
|
367
435
|
eventUnsubscribers.length = 0;
|
|
@@ -30,6 +30,8 @@ function stableStringify(value) {
|
|
|
30
30
|
if (value === null || value === void 0) return "";
|
|
31
31
|
if (typeof value !== "object") return String(value);
|
|
32
32
|
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
33
|
+
if (value instanceof RegExp) return `/${value.source}/${value.flags}`;
|
|
34
|
+
if (value instanceof Date) return `d${value.getTime()}`;
|
|
33
35
|
return "{" + Object.keys(value).sort().map((k) => `${k}:${stableStringify(value[k])}`).join(",") + "}";
|
|
34
36
|
}
|
|
35
37
|
function djb2(str) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-BpYLSNr0.mjs";
|
|
2
|
+
import { arcLog } from "./logger/index.mjs";
|
|
2
3
|
import { readdir } from "node:fs/promises";
|
|
3
4
|
import { dirname, join, resolve } from "node:path";
|
|
4
5
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
@@ -58,8 +59,9 @@ var loadResources_exports = /* @__PURE__ */ __exportAll({ loadResources: () => l
|
|
|
58
59
|
* ```
|
|
59
60
|
*/
|
|
60
61
|
async function loadResources(dir, options = {}) {
|
|
61
|
-
const { suffix = ".resource", recursive = true, exclude, include
|
|
62
|
-
const
|
|
62
|
+
const { suffix = ".resource", recursive = true, exclude, include } = options;
|
|
63
|
+
const absDir = resolve(dir.startsWith("file://") ? dirname(fileURLToPath(dir)) : dir);
|
|
64
|
+
const files = await collectFiles(absDir, new RegExp(`${escapeRegex(suffix)}\\.(ts|js|mts|mjs)$`), recursive);
|
|
63
65
|
files.sort();
|
|
64
66
|
const includeSet = include ? new Set(include) : null;
|
|
65
67
|
const excludeSet = exclude ? new Set(exclude) : null;
|
|
@@ -98,13 +100,30 @@ async function loadResources(dir, options = {}) {
|
|
|
98
100
|
return null;
|
|
99
101
|
}));
|
|
100
102
|
const resources = [];
|
|
103
|
+
const factoryFailed = [];
|
|
101
104
|
for (const result of results) {
|
|
102
105
|
if (!result) continue;
|
|
103
|
-
let resource
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
let resource;
|
|
107
|
+
const rawDefault = result.mod.default;
|
|
108
|
+
if (typeof rawDefault === "function" && !("toPlugin" in rawDefault)) try {
|
|
109
|
+
const built = await rawDefault(options.context);
|
|
110
|
+
if (built && typeof built === "object" && typeof built.toPlugin === "function") resource = built;
|
|
111
|
+
else {
|
|
112
|
+
factoryFailed.push(`${result.file}: factory returned non-resource value`);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
} catch (err) {
|
|
116
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
117
|
+
factoryFailed.push(`${result.file}: factory threw: ${msg}`);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
resource = rawDefault ?? result.mod.resource;
|
|
122
|
+
if (!resource || typeof resource.toPlugin !== "function") {
|
|
123
|
+
for (const value of Object.values(result.mod)) if (value && typeof value === "object" && typeof value.toPlugin === "function") {
|
|
124
|
+
resource = value;
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
108
127
|
}
|
|
109
128
|
}
|
|
110
129
|
if (!resource || typeof resource.toPlugin !== "function") {
|
|
@@ -118,16 +137,21 @@ async function loadResources(dir, options = {}) {
|
|
|
118
137
|
}
|
|
119
138
|
resources.push(resource);
|
|
120
139
|
}
|
|
121
|
-
const log =
|
|
140
|
+
const log = options?.logger ?? arcLog("loadResources");
|
|
122
141
|
if (log) {
|
|
123
142
|
if (failed.length) {
|
|
124
143
|
log.warn(`[arc] loadResources: ${failed.length} file(s) failed to import:`);
|
|
125
144
|
for (const f of failed) log.warn(` - ${f}`);
|
|
126
145
|
}
|
|
146
|
+
if (factoryFailed.length) {
|
|
147
|
+
log.warn(`[arc] loadResources: ${factoryFailed.length} factory export(s) failed (function default that returned non-resource or threw):`);
|
|
148
|
+
for (const f of factoryFailed) log.warn(` - ${f}`);
|
|
149
|
+
}
|
|
127
150
|
if (skipped.length) {
|
|
128
151
|
log.warn(`[arc] loadResources: ${skipped.length} file(s) skipped (no default export with toPlugin):`);
|
|
129
152
|
for (const f of skipped) log.warn(` - ${f}`);
|
|
130
153
|
}
|
|
154
|
+
if (resources.length === 0 && files.length === 0) log.warn(`[arc] loadResources: 0 matching files found at "${absDir}" (pattern: *${suffix}.{ts,js,mts,mjs}). Check the path and runtime layout (src/ vs dist/).`);
|
|
131
155
|
}
|
|
132
156
|
return resources;
|
|
133
157
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { I as MiddlewareHandler, L as RequestWithExtras,
|
|
1
|
+
import { I as MiddlewareHandler, L as RequestWithExtras, Q as MiddlewareConfig } from "../index-C_bgx9o4.mjs";
|
|
2
2
|
import { RouteHandlerMethod } from "fastify";
|
|
3
3
|
|
|
4
4
|
//#region src/middleware/middleware.d.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as CRUD_OPERATIONS } from "../constants-BhY1OHoH.mjs";
|
|
2
|
-
import { t as multipartBody } from "../multipartBody-
|
|
2
|
+
import { t as multipartBody } from "../multipartBody-CvTR1Un6.mjs";
|
|
3
3
|
//#region src/middleware/middleware.ts
|
|
4
4
|
/**
|
|
5
5
|
* Named Middleware — Priority-based, conditional middleware execution.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { t as getUserRoles } from "./types-
|
|
2
|
-
import { n as convertRouteSchema } from "./schemaConverter-
|
|
3
|
-
import { t as resolveActionPermission } from "./actionPermissions-
|
|
4
|
-
import { t as buildActionBodySchema } from "./createActionRouter-
|
|
1
|
+
import { t as getUserRoles } from "./types-DV9WDfeg.mjs";
|
|
2
|
+
import { n as convertRouteSchema } from "./schemaConverter-B0oKLuqI.mjs";
|
|
3
|
+
import { t as resolveActionPermission } from "./actionPermissions-C8YYU92K.mjs";
|
|
4
|
+
import { t as buildActionBodySchema } from "./createActionRouter-BwaSM0No.mjs";
|
|
5
5
|
import fp from "fastify-plugin";
|
|
6
6
|
//#region src/docs/openapi.ts
|
|
7
7
|
const openApiPlugin = async (fastify, opts = {}) => {
|
package/dist/org/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { yt as RouteHandler } from "../index-C_bgx9o4.mjs";
|
|
2
2
|
import { d as UserBase } from "../fields-C8Y0XLAu.mjs";
|
|
3
3
|
import { InvitationAdapter, InvitationDoc, MemberDoc, OrgAdapter, OrgDoc, OrgPermissionStatement, OrgRole, OrganizationPluginOptions } from "./types.mjs";
|
|
4
4
|
import { FastifyPluginAsync, RouteHandlerMethod } from "fastify";
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { a as applyFieldWritePermissions, c as PermissionCheck, d as UserBase, f as getUserRoles, i as applyFieldReadPermissions, l as PermissionContext, n as FieldPermissionMap, o as fields, p as normalizeRoles, r as FieldPermissionType, s as resolveEffectiveRoles, t as FieldPermission, u as PermissionResult } from "../fields-C8Y0XLAu.mjs";
|
|
2
|
-
import { A as requireRoles, C as allOf, D as not, E as denyAll, M as when, N as applyPermissionResult, O as requireAuth, P as normalizePermissionResult, S as createOrgPermissions, T as anyOf, _ as ConnectEventsOptions, a as presets_d_exports, b as PermissionEventBus, c as readOnly, d as requireOrgRole, f as requireScopeContext, g as createRoleHierarchy, h as RoleHierarchy, i as ownerWithAdminBypass, j as roles, k as requireOwnership, l as requireOrgInScope, m as requireTeamMembership, n as authenticated, o as publicRead, p as requireServiceScope, r as fullPublic, s as publicReadAdminWrite, t as adminOnly, u as requireOrgMembership, v as DynamicPermissionMatrix, w as allowPublic, x as createDynamicPermissionMatrix, y as DynamicPermissionMatrixConfig } from "../index-
|
|
2
|
+
import { A as requireRoles, C as allOf, D as not, E as denyAll, M as when, N as applyPermissionResult, O as requireAuth, P as normalizePermissionResult, S as createOrgPermissions, T as anyOf, _ as ConnectEventsOptions, a as presets_d_exports, b as PermissionEventBus, c as readOnly, d as requireOrgRole, f as requireScopeContext, g as createRoleHierarchy, h as RoleHierarchy, i as ownerWithAdminBypass, j as roles, k as requireOwnership, l as requireOrgInScope, m as requireTeamMembership, n as authenticated, o as publicRead, p as requireServiceScope, r as fullPublic, s as publicReadAdminWrite, t as adminOnly, u as requireOrgMembership, v as DynamicPermissionMatrix, w as allowPublic, x as createDynamicPermissionMatrix, y as DynamicPermissionMatrixConfig } from "../index-BYCqHCVu.mjs";
|
|
3
3
|
export { ConnectEventsOptions, DynamicPermissionMatrix, DynamicPermissionMatrixConfig, FieldPermission, FieldPermissionMap, FieldPermissionType, PermissionCheck, PermissionContext, PermissionEventBus, PermissionResult, RoleHierarchy, UserBase, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, applyPermissionResult, authenticated, createDynamicPermissionMatrix, createOrgPermissions, createRoleHierarchy, denyAll, fields, fullPublic, getUserRoles, normalizePermissionResult, normalizeRoles, not, ownerWithAdminBypass, presets_d_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAuth, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, resolveEffectiveRoles, roles, when };
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as normalizeRoles, t as getUserRoles } from "../types-
|
|
3
|
-
import { n as normalizePermissionResult, t as applyPermissionResult } from "../applyPermissionResult-QhV1Pa-g.mjs";
|
|
4
|
-
import { C as requireAuth, D as when, E as roles, S as not, T as requireRoles, _ as requireTeamMembership, a as presets_exports, b as anyOf, c as readOnly, d as createOrgPermissions, f as requireOrgInScope, g as requireServiceScope, h as requireScopeContext, i as ownerWithAdminBypass, l as createRoleHierarchy, m as requireOrgRole, n as authenticated, o as publicRead, p as requireOrgMembership, r as fullPublic, s as publicReadAdminWrite, t as adminOnly, u as createDynamicPermissionMatrix, v as allOf, w as requireOwnership, x as denyAll, y as allowPublic } from "../permissions-wkqRwicB.mjs";
|
|
1
|
+
import { A as normalizePermissionResult, C as requireAuth, D as when, E as roles, M as applyFieldWritePermissions, N as fields, O as applyPermissionResult, P as resolveEffectiveRoles, S as not, T as requireRoles, _ as requireTeamMembership, a as presets_exports, b as anyOf, c as readOnly, d as createOrgPermissions, f as requireOrgInScope, g as requireServiceScope, h as requireScopeContext, i as ownerWithAdminBypass, j as applyFieldReadPermissions, l as createRoleHierarchy, m as requireOrgRole, n as authenticated, o as publicRead, p as requireOrgMembership, r as fullPublic, s as publicReadAdminWrite, t as adminOnly, u as createDynamicPermissionMatrix, v as allOf, w as requireOwnership, x as denyAll, y as allowPublic } from "../permissions-B4vU9L0Q.mjs";
|
|
2
|
+
import { n as normalizeRoles, t as getUserRoles } from "../types-DV9WDfeg.mjs";
|
|
5
3
|
export { adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, applyPermissionResult, authenticated, createDynamicPermissionMatrix, createOrgPermissions, createRoleHierarchy, denyAll, fields, fullPublic, getUserRoles, normalizePermissionResult, normalizeRoles, not, ownerWithAdminBypass, presets_exports as permissions, publicRead, publicReadAdminWrite, readOnly, requireAuth, requireOrgInScope, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireScopeContext, requireServiceScope, requireTeamMembership, resolveEffectiveRoles, roles, when };
|