@lunora/server 1.0.0-alpha.4 → 1.0.0-alpha.40

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.
Files changed (68) hide show
  1. package/LICENSE.md +219 -0
  2. package/README.md +50 -0
  3. package/dist/data-model.d.mts +231 -156
  4. package/dist/data-model.d.ts +231 -156
  5. package/dist/data-model.mjs +0 -1
  6. package/dist/drizzle.mjs +1 -1
  7. package/dist/index.d.mts +1304 -831
  8. package/dist/index.d.ts +1304 -831
  9. package/dist/index.mjs +1 -24
  10. package/dist/otel.d.mts +543 -0
  11. package/dist/otel.d.ts +543 -0
  12. package/dist/otel.mjs +1 -0
  13. package/dist/packem_shared/LunoraEnvError-CgpI2Mm_.mjs +3 -0
  14. package/dist/packem_shared/LunoraError-LVhdU0Lo.mjs +1 -0
  15. package/dist/packem_shared/PRESENCE_DEFAULT_TTL_MS-CF_9uiu1.mjs +1 -0
  16. package/dist/packem_shared/allowAll-BnyNbJZT.mjs +1 -0
  17. package/dist/packem_shared/asBucketStorage-1pFfH-Tn.mjs +1 -0
  18. package/dist/packem_shared/bindOrm-Bp9hsM2q.mjs +1 -0
  19. package/dist/packem_shared/buildRlsReadRegistry-WdiqSj87.mjs +1 -0
  20. package/dist/packem_shared/composePluginMiddleware-COr09CXA.mjs +1 -0
  21. package/dist/packem_shared/context-identity-GunnA6La.mjs +1 -0
  22. package/dist/packem_shared/createPolicyDsl-sV1swpkD.mjs +1 -0
  23. package/dist/packem_shared/createSecrets-CgVPiW2C.mjs +1 -0
  24. package/dist/packem_shared/defineAggregateIndex-CYuH6IbJ.mjs +1 -0
  25. package/dist/packem_shared/defineIdentity-B7gfAgxx.mjs +1 -0
  26. package/dist/packem_shared/defineMigration-Bfpwxv2f.mjs +1 -0
  27. package/dist/packem_shared/defineMutator-BgpQ-xUo.mjs +1 -0
  28. package/dist/packem_shared/defineShape-Ds8uNqzX.mjs +1 -0
  29. package/dist/packem_shared/defineStorageRule-BDu01PUn.mjs +1 -0
  30. package/dist/packem_shared/functions-CDC08CWY.mjs +1 -0
  31. package/dist/packem_shared/httpAction-C14NuF3V.mjs +4 -0
  32. package/dist/packem_shared/initLunora-CHh1EmR4.mjs +1 -0
  33. package/dist/packem_shared/mask-C6Bi78qj.mjs +1 -0
  34. package/dist/packem_shared/onConnect-CEtRmUpJ.mjs +1 -0
  35. package/dist/packem_shared/policy-tag-Dprt9JWo.mjs +1 -0
  36. package/dist/packem_shared/protectPublic-BhKewPqm.mjs +1 -0
  37. package/dist/packem_shared/rls-_iVsPvhX.mjs +1 -0
  38. package/dist/packem_shared/run-middleware-BeEEqmdE.mjs +1 -0
  39. package/dist/packem_shared/storageRules-BptPZbi8.mjs +1 -0
  40. package/dist/packem_shared/types.d-C4CMJK8x.d.mts +141 -0
  41. package/dist/packem_shared/types.d-DdYF8E18.d.ts +141 -0
  42. package/dist/rls/testing.d.mts +31 -31
  43. package/dist/rls/testing.d.ts +31 -31
  44. package/dist/rls/testing.mjs +1 -49
  45. package/dist/types.d.mts +1163 -440
  46. package/dist/types.d.ts +1163 -440
  47. package/dist/types.mjs +1 -31
  48. package/package.json +18 -5
  49. package/dist/packem_shared/LunoraEnvError-DjFkpkSP.mjs +0 -187
  50. package/dist/packem_shared/LunoraError-DhggBJZF.mjs +0 -51
  51. package/dist/packem_shared/PRESENCE_DEFAULT_TTL_MS-BgBQsqQ-.mjs +0 -114
  52. package/dist/packem_shared/asBucketStorage-Cnxd9y2q.mjs +0 -11
  53. package/dist/packem_shared/bindOrm-Ce57S3N9.mjs +0 -128
  54. package/dist/packem_shared/composePluginMiddleware-Ck5_TUO8.mjs +0 -100
  55. package/dist/packem_shared/createPolicyDsl-De67zPDS.mjs +0 -29
  56. package/dist/packem_shared/defineAggregateIndex-C2gT1GzM.mjs +0 -252
  57. package/dist/packem_shared/defineMigration-CAJLr6fx.mjs +0 -8
  58. package/dist/packem_shared/defineStorageRule-qu0mpilX.mjs +0 -20
  59. package/dist/packem_shared/httpAction-B7FYUEgr.mjs +0 -340
  60. package/dist/packem_shared/initLunora-CATvPsVt.mjs +0 -86
  61. package/dist/packem_shared/mask-eCUYOwhd.mjs +0 -211
  62. package/dist/packem_shared/onConnect-CIPXKPyw.mjs +0 -13
  63. package/dist/packem_shared/protectPublic-BjFkQ_Or.mjs +0 -15
  64. package/dist/packem_shared/rls-Bi9HiyDC.mjs +0 -567
  65. package/dist/packem_shared/run-middleware-CYQOuoV6.mjs +0 -18
  66. package/dist/packem_shared/storageRules-4a30FSpI.mjs +0 -88
  67. package/dist/packem_shared/types.d-BDY0FYHK.d.ts +0 -135
  68. package/dist/packem_shared/types.d-DmvyEMD6.d.mts +0 -135
@@ -1,86 +0,0 @@
1
- import { parseValidatorMap } from '@lunora/values';
2
- import { r as runMiddlewareChain } from './run-middleware-CYQOuoV6.mjs';
3
-
4
- const validateArgs = (validators, args) => parseValidatorMap(validators, args, "args");
5
-
6
- const runMiddleware = (middlewares, baseContext) => runMiddlewareChain(middlewares, baseContext, (context) => context);
7
- const makeHandler = (args, middlewares, userHandler, output) => async (context, rawArgs) => {
8
- const parsed = validateArgs(args, rawArgs);
9
- const resolvedContext = await runMiddleware(middlewares, context);
10
- const result = await userHandler({ args: parsed, ctx: resolvedContext });
11
- return output ? output.parse(result) : result;
12
- };
13
- const makeStreamHandler = (args, middlewares, userHandler) => (context, rawArgs, signal) => {
14
- const parsed = validateArgs(args, rawArgs);
15
- return (async function* drive() {
16
- const resolvedContext = await runMiddleware(middlewares, context);
17
- const source = userHandler({ args: parsed, ctx: resolvedContext, signal });
18
- const iterator = source[Symbol.asyncIterator]();
19
- try {
20
- while (true) {
21
- if (signal.aborted) {
22
- return;
23
- }
24
- const next = await iterator.next();
25
- if (next.done) {
26
- return;
27
- }
28
- if (signal.aborted) {
29
- return;
30
- }
31
- yield next.value;
32
- }
33
- } finally {
34
- await iterator.return?.();
35
- }
36
- })();
37
- };
38
- const makeBuilder = (kind, state, visibility) => {
39
- return {
40
- __lunoraProcedure: kind,
41
- ...visibility ? { __lunoraVisibility: visibility } : {},
42
- input: (validators) => makeBuilder(kind, { ...state, args: { ...state.args, ...validators } }, visibility),
43
- [kind]: (userHandler) => {
44
- return {
45
- args: state.args,
46
- handler: makeHandler(state.args, state.middlewares, userHandler, state.output),
47
- kind,
48
- ...visibility ? { visibility } : {}
49
- };
50
- },
51
- output: (validator) => makeBuilder(kind, { ...state, output: validator }, visibility),
52
- // `.stream()` is meaningful only on query builders. It's harmless to expose
53
- // on every builder shape (callers can't hit it from action/mutation builders
54
- // anyway since the type system narrows it away), but emitting it
55
- // unconditionally keeps the runtime free of per-kind branching.
56
- ...kind === "query" ? {
57
- stream: (userHandler) => {
58
- return {
59
- args: state.args,
60
- handler: makeStreamHandler(state.args, state.middlewares, userHandler),
61
- kind: "stream",
62
- ...visibility ? { visibility } : {}
63
- };
64
- }
65
- } : {},
66
- use: (middleware) => makeBuilder(kind, { ...state, middlewares: [...state.middlewares, middleware] }, visibility)
67
- };
68
- };
69
- const initLunora = {
70
- dataModel: () => {
71
- return {
72
- create: (_options) => {
73
- return {
74
- action: makeBuilder("action", { args: {}, middlewares: [] }),
75
- internalAction: makeBuilder("action", { args: {}, middlewares: [] }, "internal"),
76
- internalMutation: makeBuilder("mutation", { args: {}, middlewares: [] }, "internal"),
77
- internalQuery: makeBuilder("query", { args: {}, middlewares: [] }, "internal"),
78
- mutation: makeBuilder("mutation", { args: {}, middlewares: [] }),
79
- query: makeBuilder("query", { args: {}, middlewares: [] })
80
- };
81
- }
82
- };
83
- }
84
- };
85
-
86
- export { initLunora };
@@ -1,211 +0,0 @@
1
- import { LunoraError } from './LunoraError-DhggBJZF.mjs';
2
- import { bindTableFacade, bindOrm } from './bindOrm-Ce57S3N9.mjs';
3
-
4
- const permissionName = (permission) => typeof permission === "string" ? permission : permission.name;
5
- const indexRolePermissions = (roles) => {
6
- const map = /* @__PURE__ */ new Map();
7
- for (const role of roles ?? []) {
8
- map.set(role.name, new Set((role.permissions ?? []).map((permission) => permissionName(permission))));
9
- }
10
- return map;
11
- };
12
- const fnv1aHex = (input) => {
13
- let hash = 2166136261;
14
- for (let index = 0; index < input.length; index += 1) {
15
- hash ^= input.codePointAt(index) ?? 0;
16
- hash = Math.imul(hash, 16777619);
17
- }
18
- return (hash >>> 0).toString(16).padStart(8, "0");
19
- };
20
- const applyStrategy = (strategy, value, context) => {
21
- try {
22
- if (strategy === "redact") {
23
- return null;
24
- }
25
- if (strategy === "hash") {
26
- if (value === null || value === void 0) {
27
- return value;
28
- }
29
- return fnv1aHex(typeof value === "string" ? value : JSON.stringify(value));
30
- }
31
- return strategy(value, context);
32
- } catch {
33
- return null;
34
- }
35
- };
36
- const maskRow = (row, columns, base) => {
37
- const out = { ...row };
38
- for (const [column, strategy] of Object.entries(columns)) {
39
- if (!(column in out)) {
40
- continue;
41
- }
42
- out[column] = applyStrategy(strategy, row[column], { ...base, column, row });
43
- }
44
- return out;
45
- };
46
- const maskPage = (page, columns, base) => {
47
- return { ...page, page: page.page.map((row) => maskRow(row, columns, base)) };
48
- };
49
- const isFacadeEntry = (value) => {
50
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
51
- return false;
52
- }
53
- const candidate = value;
54
- return typeof candidate["findMany"] === "function" && typeof candidate["withSearchIndex"] === "function";
55
- };
56
- const wrapDatabase = (base, perTable, context) => {
57
- const wrapReader = (reader, columns) => {
58
- return {
59
- collect: async () => {
60
- const rows = await reader.collect();
61
- return rows.map((row) => maskRow(row, columns, context));
62
- },
63
- filter: (predicate) => wrapReader(
64
- reader.filter((document) => predicate(document)),
65
- columns
66
- ),
67
- first: async () => {
68
- const row = await reader.first();
69
- return row ? maskRow(row, columns, context) : null;
70
- },
71
- order: (direction) => wrapReader(reader.order(direction), columns),
72
- paginate: async (options) => maskPage(await reader.paginate(options), columns, context),
73
- take: async (limit) => {
74
- const rows = await reader.take(limit);
75
- return rows.map((row) => maskRow(row, columns, context));
76
- },
77
- unique: async () => {
78
- const row = await reader.unique();
79
- return row ? maskRow(row, columns, context) : null;
80
- },
81
- withIndex: (indexName, range) => wrapReader(reader.withIndex(indexName, range), columns),
82
- withSearchIndex: (indexName, search) => wrapReader(reader.withSearchIndex(indexName, search), columns)
83
- };
84
- };
85
- const locate = async (id, expectedTable) => {
86
- if (base.lookupById) {
87
- const located = await base.lookupById(id, expectedTable);
88
- if (!located) {
89
- return { row: null, tableName: void 0 };
90
- }
91
- return { row: located.row, tableName: perTable.has(located.tableName) ? located.tableName : void 0 };
92
- }
93
- const row = await base.get(id, expectedTable);
94
- if (!row) {
95
- return { row: null, tableName: void 0 };
96
- }
97
- let probeTables;
98
- if (expectedTable === void 0) {
99
- probeTables = [...perTable.keys()];
100
- } else if (perTable.has(expectedTable)) {
101
- probeTables = [expectedTable];
102
- } else {
103
- probeTables = [];
104
- }
105
- const probes = await Promise.all(
106
- probeTables.map(async (tableName) => {
107
- const probe = await base.findFirst(tableName, { limit: 1, where: { _id: id } });
108
- return probe?.["_id"] === id ? tableName : void 0;
109
- })
110
- );
111
- return { row, tableName: probes.find((entry) => entry !== void 0) };
112
- };
113
- const assertReductionAllowed = (tableName, fields, method) => {
114
- const columns = perTable.get(tableName);
115
- if (!columns) {
116
- return;
117
- }
118
- const offending = fields.find((field) => typeof field === "string" && field in columns);
119
- if (offending !== void 0) {
120
- throw new LunoraError("MASK_UNSUPPORTED", `${method}() over masked column "${offending}" on "${tableName}" is not supported`);
121
- }
122
- };
123
- const wrapped = {
124
- ...base,
125
- aggregate(tableName, options) {
126
- assertReductionAllowed(tableName, [options.field], "aggregate");
127
- return base.aggregate(tableName, options);
128
- },
129
- async findFirst(tableName, args) {
130
- const row = await base.findFirst(tableName, args);
131
- const columns = perTable.get(tableName);
132
- return row && columns ? maskRow(row, columns, context) : row;
133
- },
134
- async findFirstOrThrow(tableName, args) {
135
- const row = await base.findFirstOrThrow(tableName, args);
136
- const columns = perTable.get(tableName);
137
- return columns ? maskRow(row, columns, context) : row;
138
- },
139
- async findMany(tableName, args) {
140
- const page = await base.findMany(tableName, args);
141
- const columns = perTable.get(tableName);
142
- return columns ? maskPage(page, columns, context) : page;
143
- },
144
- async get(id, expectedTable) {
145
- const { row, tableName } = await locate(id, expectedTable);
146
- const columns = tableName === void 0 ? void 0 : perTable.get(tableName);
147
- if (!row || !columns) {
148
- return row;
149
- }
150
- return maskRow(row, columns, context);
151
- },
152
- groupBy(tableName, options) {
153
- assertReductionAllowed(tableName, [...options.by, options.agg?.field], "groupBy");
154
- return base.groupBy(tableName, options);
155
- },
156
- query(tableName) {
157
- const reader = base.query(tableName);
158
- const columns = perTable.get(tableName);
159
- return columns ? wrapReader(reader, columns) : reader;
160
- },
161
- async rankPage(tableName, indexName, options) {
162
- const page = await base.rankPage(tableName, indexName, options);
163
- const columns = perTable.get(tableName);
164
- return columns ? maskPage(page, columns, context) : page;
165
- }
166
- };
167
- const writableFacade = wrapped;
168
- for (const tableName of perTable.keys()) {
169
- if (isFacadeEntry(base[tableName])) {
170
- writableFacade[tableName] = bindTableFacade(wrapped, tableName);
171
- }
172
- }
173
- return wrapped;
174
- };
175
- const mask = (policies, options = {}) => {
176
- const perTable = new Map(Object.entries(policies));
177
- const rolePermissions = indexRolePermissions(options.roles);
178
- return async ({ ctx, next }) => {
179
- const auth = ctx.auth ?? {};
180
- const identity = await auth.getIdentity?.() ?? null;
181
- const roles = auth.roles ?? [];
182
- const granted = /* @__PURE__ */ new Set();
183
- for (const roleName of roles) {
184
- for (const name of rolePermissions.get(roleName) ?? []) {
185
- granted.add(name);
186
- }
187
- }
188
- const maskContext = {
189
- auth: {
190
- can: (permission) => granted.has(permissionName(permission)),
191
- identity,
192
- roles,
193
- // eslint-disable-next-line unicorn/no-null -- MaskContext.auth.userId is a public `null | string` type
194
- userId: auth.userId ?? null
195
- },
196
- ctx
197
- };
198
- if (options.bypass?.(maskContext)) {
199
- return next();
200
- }
201
- const wrapped = wrapDatabase(ctx.db, perTable, maskContext);
202
- const extension = { db: wrapped };
203
- const { orm } = ctx;
204
- if (orm !== null && typeof orm === "object") {
205
- extension.orm = bindOrm(wrapped);
206
- }
207
- return next({ ctx: extension });
208
- };
209
- };
210
-
211
- export { mask };
@@ -1,13 +0,0 @@
1
- const wrapLifecycle = (lifecycle, handler) => {
2
- return {
3
- args: {},
4
- handler: (context, event) => handler(context, event),
5
- kind: "mutation",
6
- lifecycle,
7
- visibility: "internal"
8
- };
9
- };
10
- const onConnect = (handler) => wrapLifecycle("connect", handler);
11
- const onDisconnect = (handler) => wrapLifecycle("disconnect", handler);
12
-
13
- export { onConnect, onDisconnect };
@@ -1,15 +0,0 @@
1
- import { r as runMiddlewareChain } from './run-middleware-CYQOuoV6.mjs';
2
-
3
- const protectPublic = (options) => {
4
- const chain = [options.rateLimit, options.captcha, ...options.use ?? []].filter(
5
- (middleware) => middleware !== void 0
6
- );
7
- const composed = async ({ ctx, next }) => runMiddlewareChain(
8
- chain,
9
- ctx,
10
- (context) => next({ ctx: context })
11
- );
12
- return composed;
13
- };
14
-
15
- export { protectPublic };