@aventara/access 0.0.0-stage → 1.0.0-rc.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/CHANGELOG.md +877 -0
- package/LICENSE +91 -0
- package/LICENSE-ADDITIONAL-PERMISSION.md +9 -0
- package/README.md +2536 -2
- package/dist/access/access-options.d.ts +74 -0
- package/dist/access/access-options.js +5 -0
- package/dist/access/access.error.d.ts +35 -0
- package/dist/access/access.error.js +11 -0
- package/dist/access/access.factory.d.ts +275 -0
- package/dist/access/access.factory.js +440 -0
- package/dist/access/better-auth.hardening.d.ts +120 -0
- package/dist/access/better-auth.hardening.js +420 -0
- package/dist/access/better-auth.loader.d.ts +67 -0
- package/dist/access/better-auth.loader.js +65 -0
- package/dist/access/better-auth.range.d.ts +9 -0
- package/dist/access/better-auth.range.js +28 -0
- package/dist/access/better-auth.require.d.ts +90 -0
- package/dist/access/better-auth.require.js +6 -0
- package/dist/access/better-auth.require.node.d.ts +7 -0
- package/dist/access/better-auth.require.node.js +52 -0
- package/dist/access/claims.mapper.d.ts +79 -0
- package/dist/access/claims.mapper.js +152 -0
- package/dist/access/key-set.cache.d.ts +10 -0
- package/dist/access/key-set.cache.js +63 -0
- package/dist/access/policies-block.checker.d.ts +64 -0
- package/dist/access/policies-block.checker.js +138 -0
- package/dist/access/principal.subject.d.ts +22 -0
- package/dist/access/principal.subject.js +89 -0
- package/dist/access/profile.policy.d.ts +74 -0
- package/dist/access/profile.policy.js +110 -0
- package/dist/access/request.state.d.ts +89 -0
- package/dist/access/request.state.js +266 -0
- package/dist/access/session.hooks.d.ts +114 -0
- package/dist/access/session.hooks.js +258 -0
- package/dist/access/token.verifier.d.ts +35 -0
- package/dist/access/token.verifier.js +69 -0
- package/dist/access-schema.d.ts +48 -0
- package/dist/access-schema.js +5 -0
- package/dist/access-warning.emitter.d.ts +4 -0
- package/dist/access-warning.emitter.js +24 -0
- package/dist/access.builder.d.ts +340 -0
- package/dist/access.builder.js +75 -0
- package/dist/access.engine.d.ts +155 -0
- package/dist/access.engine.js +477 -0
- package/dist/audit/audit-event.d.ts +135 -0
- package/dist/audit/audit-event.js +8 -0
- package/dist/audit/audit.log.d.ts +122 -0
- package/dist/audit/audit.log.js +345 -0
- package/dist/audit/audit.schema.d.ts +143 -0
- package/dist/audit/audit.schema.js +50 -0
- package/dist/auth/index.d.ts +12 -0
- package/dist/auth/index.js +2 -0
- package/dist/aventara-where.translator.d.ts +19 -0
- package/dist/aventara-where.translator.js +87 -0
- package/dist/beacon/beacon.check.d.ts +59 -0
- package/dist/beacon/beacon.check.js +128 -0
- package/dist/beacon/beacon.schema.d.ts +41 -0
- package/dist/beacon/beacon.schema.js +48 -0
- package/dist/beacon/beacon.store.d.ts +29 -0
- package/dist/beacon/beacon.store.js +78 -0
- package/dist/better-auth/access.client-plugin.d.ts +75 -0
- package/dist/better-auth/access.client-plugin.js +133 -0
- package/dist/better-auth/access.plugin.d.ts +164 -0
- package/dist/better-auth/access.plugin.js +348 -0
- package/dist/better-auth/access.provider.d.ts +80 -0
- package/dist/better-auth/access.provider.js +100 -0
- package/dist/better-auth/index.d.ts +7 -0
- package/dist/better-auth/index.js +4 -0
- package/dist/better-auth/organization.bridge.d.ts +66 -0
- package/dist/better-auth/organization.bridge.js +144 -0
- package/dist/canonical-json.writer.d.ts +12 -0
- package/dist/canonical-json.writer.js +30 -0
- package/dist/cli/avaccess.bin.d.ts +2 -0
- package/dist/cli/avaccess.bin.js +26 -0
- package/dist/cli/avaccess.program.d.ts +15 -0
- package/dist/cli/avaccess.program.js +166 -0
- package/dist/cli/beacon-pins.file.d.ts +14 -0
- package/dist/cli/beacon-pins.file.js +62 -0
- package/dist/cli/beacon.loader.d.ts +20 -0
- package/dist/cli/beacon.loader.js +71 -0
- package/dist/cli/cli.context.d.ts +49 -0
- package/dist/cli/cli.context.js +66 -0
- package/dist/cli/diff.command.d.ts +2 -0
- package/dist/cli/diff.command.js +66 -0
- package/dist/cli/generate.command.d.ts +2 -0
- package/dist/cli/generate.command.js +82 -0
- package/dist/cli/keys.command.d.ts +2 -0
- package/dist/cli/keys.command.js +96 -0
- package/dist/cli/lock.file.d.ts +31 -0
- package/dist/cli/lock.file.js +181 -0
- package/dist/cli/module.loader.d.ts +13 -0
- package/dist/cli/module.loader.js +63 -0
- package/dist/cli/policies.diff.d.ts +16 -0
- package/dist/cli/policies.diff.js +101 -0
- package/dist/cli/pull.command.d.ts +2 -0
- package/dist/cli/pull.command.js +234 -0
- package/dist/cli/push.command.d.ts +2 -0
- package/dist/cli/push.command.js +59 -0
- package/dist/cli/registry.client.d.ts +63 -0
- package/dist/cli/registry.client.js +287 -0
- package/dist/cli/schema.command.d.ts +2 -0
- package/dist/cli/schema.command.js +60 -0
- package/dist/cli/serve.command.d.ts +6 -0
- package/dist/cli/serve.command.js +200 -0
- package/dist/cli/status.command.d.ts +2 -0
- package/dist/cli/status.command.js +31 -0
- package/dist/cli/translator.flag.d.ts +6 -0
- package/dist/cli/translator.flag.js +24 -0
- package/dist/cli/verify.command.d.ts +2 -0
- package/dist/cli/verify.command.js +40 -0
- package/dist/client/access-client.factory.d.ts +92 -0
- package/dist/client/access-client.factory.js +269 -0
- package/dist/client/access-verbs.schema.d.ts +66 -0
- package/dist/client/access-verbs.schema.js +159 -0
- package/dist/client/verb-rate.limiter.d.ts +116 -0
- package/dist/client/verb-rate.limiter.js +358 -0
- package/dist/foreign/foreign-facts.d.ts +30 -0
- package/dist/foreign/foreign-facts.js +75 -0
- package/dist/foreign/foreign.merger.d.ts +10 -0
- package/dist/foreign/foreign.merger.js +52 -0
- package/dist/foreign-references.check.d.ts +6 -0
- package/dist/foreign-references.check.js +131 -0
- package/dist/generator/client.emitter.d.ts +28 -0
- package/dist/generator/client.emitter.js +411 -0
- package/dist/generator/copied-modules.reader.d.ts +14 -0
- package/dist/generator/copied-modules.reader.js +80 -0
- package/dist/generator/namespace.facts.d.ts +28 -0
- package/dist/generator/namespace.facts.js +32 -0
- package/dist/generator/orm.translator.d.ts +48 -0
- package/dist/generator/orm.translator.js +29 -0
- package/dist/generator/prisma7/prisma-schema.reader.d.ts +9 -0
- package/dist/generator/prisma7/prisma-schema.reader.js +394 -0
- package/dist/generator/prisma7/prisma-where.translator.d.ts +73 -0
- package/dist/generator/prisma7/prisma-where.translator.js +138 -0
- package/dist/generator/prisma7/prisma7.translator.d.ts +2 -0
- package/dist/generator/prisma7/prisma7.translator.js +87 -0
- package/dist/generator/schema.emitter.d.ts +14 -0
- package/dist/generator/schema.emitter.js +23 -0
- package/dist/generator/tsconfig.reader.d.ts +44 -0
- package/dist/generator/tsconfig.reader.js +110 -0
- package/dist/generator/typescript-literal.writer.d.ts +5 -0
- package/dist/generator/typescript-literal.writer.js +42 -0
- package/dist/guardrails/guardrails-contract.d.ts +45 -0
- package/dist/guardrails/guardrails-contract.js +12 -0
- package/dist/guardrails/guardrails.builder.d.ts +48 -0
- package/dist/guardrails/guardrails.builder.js +32 -0
- package/dist/guardrails/guardrails.compiler.d.ts +10 -0
- package/dist/guardrails/guardrails.compiler.js +254 -0
- package/dist/guardrails/guardrails.composer.d.ts +7 -0
- package/dist/guardrails/guardrails.composer.js +95 -0
- package/dist/guardrails/guardrails.hash.d.ts +10 -0
- package/dist/guardrails/guardrails.hash.js +38 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +6 -0
- package/dist/kiosk/kiosk-verbs.schema.d.ts +19 -0
- package/dist/kiosk/kiosk-verbs.schema.js +61 -0
- package/dist/kiosk/kiosk.plugin.d.ts +217 -0
- package/dist/kiosk/kiosk.plugin.js +877 -0
- package/dist/kiosk/kiosk.schema.d.ts +176 -0
- package/dist/kiosk/kiosk.schema.js +101 -0
- package/dist/kiosk/kiosk.store.d.ts +171 -0
- package/dist/kiosk/kiosk.store.js +478 -0
- package/dist/kiosk/lan-range.policy.d.ts +31 -0
- package/dist/kiosk/lan-range.policy.js +113 -0
- package/dist/kiosk/pin.policy.d.ts +9 -0
- package/dist/kiosk/pin.policy.js +143 -0
- package/dist/kiosk/session-use.marker.d.ts +4 -0
- package/dist/kiosk/session-use.marker.js +16 -0
- package/dist/lock/lock-contract.d.ts +38 -0
- package/dist/lock/lock-contract.js +67 -0
- package/dist/lock/lock.verifier.d.ts +27 -0
- package/dist/lock/lock.verifier.js +62 -0
- package/dist/mcp/agent-scope.gate.d.ts +13 -0
- package/dist/mcp/agent-scope.gate.js +75 -0
- package/dist/mcp/agent.grant.d.ts +40 -0
- package/dist/mcp/agent.grant.js +92 -0
- package/dist/mcp/mcp-options.d.ts +60 -0
- package/dist/mcp/mcp-options.js +72 -0
- package/dist/oauth/access-token.verifier.d.ts +66 -0
- package/dist/oauth/access-token.verifier.js +201 -0
- package/dist/oauth/oauth-provider.hardening.d.ts +62 -0
- package/dist/oauth/oauth-provider.hardening.js +261 -0
- package/dist/passwords/argon2id.hasher.d.ts +97 -0
- package/dist/passwords/argon2id.hasher.js +256 -0
- package/dist/passwords/node-rs-argon2.adapter.d.ts +25 -0
- package/dist/passwords/node-rs-argon2.adapter.js +42 -0
- package/dist/passwords/passwords.options.d.ts +79 -0
- package/dist/passwords/passwords.options.js +212 -0
- package/dist/policies-contract.d.ts +219 -0
- package/dist/policies-contract.js +8 -0
- package/dist/policies.compiler.d.ts +38 -0
- package/dist/policies.compiler.js +1433 -0
- package/dist/policies.decider.d.ts +103 -0
- package/dist/policies.decider.js +390 -0
- package/dist/policies.hash.d.ts +10 -0
- package/dist/policies.hash.js +54 -0
- package/dist/predicate.evaluator.d.ts +62 -0
- package/dist/predicate.evaluator.js +378 -0
- package/dist/random-secret.generator.d.ts +2 -0
- package/dist/random-secret.generator.js +15 -0
- package/dist/read-governed-unique.check.d.ts +3 -0
- package/dist/read-governed-unique.check.js +21 -0
- package/dist/reference-reads.check.d.ts +16 -0
- package/dist/reference-reads.check.js +158 -0
- package/dist/registry/access.registry.d.ts +173 -0
- package/dist/registry/access.registry.js +865 -0
- package/dist/registry/beacon.ledger.d.ts +30 -0
- package/dist/registry/beacon.ledger.js +93 -0
- package/dist/registry/ownership.check.d.ts +54 -0
- package/dist/registry/ownership.check.js +221 -0
- package/dist/registry/registry.endpoints.d.ts +50 -0
- package/dist/registry/registry.endpoints.js +193 -0
- package/dist/registry/registry.key.d.ts +7 -0
- package/dist/registry/registry.key.js +13 -0
- package/dist/registry/registry.options.d.ts +13 -0
- package/dist/registry/registry.options.js +28 -0
- package/dist/registry/registry.refusal.d.ts +6 -0
- package/dist/registry/registry.refusal.js +11 -0
- package/dist/registry/registry.schema.d.ts +238 -0
- package/dist/registry/registry.schema.js +127 -0
- package/dist/resources/auth-tables.catalog.d.ts +96 -0
- package/dist/resources/auth-tables.catalog.js +110 -0
- package/dist/resources/auth-tables.guard.d.ts +106 -0
- package/dist/resources/auth-tables.guard.js +462 -0
- package/dist/scope.resolver.d.ts +144 -0
- package/dist/scope.resolver.js +529 -0
- package/dist/sha256.digest.d.ts +2 -0
- package/dist/sha256.digest.js +81 -0
- package/dist/standalone/access.server.d.ts +41 -0
- package/dist/standalone/access.server.js +301 -0
- package/dist/standalone/index.d.ts +1 -0
- package/dist/standalone/index.js +1 -0
- package/package.json +102 -3
- package/skill/SKILL.md +170 -0
- package/skill/reference/callers.md +99 -0
- package/skill/reference/errors.md +89 -0
- package/skill/reference/recipes.md +281 -0
- package/skill/reference/rules.md +153 -0
- package/skill/reference/setup.md +334 -0
- package/src/aventara-where.translator.ts +116 -0
- package/src/beacon/beacon.check.ts +204 -0
- package/src/canonical-json.writer.ts +51 -0
- package/src/generator/prisma7/prisma-where.translator.ts +243 -0
- package/src/policies-contract.ts +215 -0
- package/src/policies.decider.ts +662 -0
- package/src/predicate.evaluator.ts +574 -0
- package/src/scope.resolver.ts +819 -0
- package/src/sha256.digest.ts +85 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AccessPolicies } from "../policies-contract.js";
|
|
2
|
+
/** One relation of a Resource, as the generated row types follow it. */
|
|
3
|
+
type RelationFacts = {
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly target: string;
|
|
6
|
+
readonly cardinality: "one" | "many";
|
|
7
|
+
};
|
|
8
|
+
/** One Resource of the namespace. */
|
|
9
|
+
export type ResourceFacts = {
|
|
10
|
+
readonly name: string;
|
|
11
|
+
/** The namespace that owns it, when it is not this file's. */
|
|
12
|
+
readonly foreign: string | undefined;
|
|
13
|
+
/** Its scalar fields, sorted. */
|
|
14
|
+
readonly fields: readonly string[];
|
|
15
|
+
/** Its relations, sorted by name. */
|
|
16
|
+
readonly relations: readonly RelationFacts[];
|
|
17
|
+
};
|
|
18
|
+
/** The namespace a generated client decides for. */
|
|
19
|
+
export type NamespaceFacts = {
|
|
20
|
+
readonly namespace: string;
|
|
21
|
+
/** Its Resources, sorted by name. */
|
|
22
|
+
readonly resources: readonly ResourceFacts[];
|
|
23
|
+
};
|
|
24
|
+
/** The facts of a pulled policies file. */
|
|
25
|
+
export declare const namespaceFactsOf: (namespace: string, policies: AccessPolicies) => NamespaceFacts;
|
|
26
|
+
/** A property key as TypeScript writes it: bare when it is an identifier, quoted otherwise. */
|
|
27
|
+
export declare const propertyKey: (name: string) => string;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// What a generated client says about its namespace, read from the pulled policies
|
|
2
|
+
// file alone: its Resources (its own and the foreign ones its rules read), each
|
|
3
|
+
// one's scalar fields and relations. The policies file names fields, never their
|
|
4
|
+
// types, so neither does the generated client. Every list is sorted, so the client's
|
|
5
|
+
// text depends on the file's content and never on its member order.
|
|
6
|
+
const byCodeUnit = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
7
|
+
/** The facts of a pulled policies file. */
|
|
8
|
+
export const namespaceFactsOf = (namespace, policies) => ({
|
|
9
|
+
namespace,
|
|
10
|
+
resources: Object.keys(policies.schema)
|
|
11
|
+
.sort(byCodeUnit)
|
|
12
|
+
.map((name) => {
|
|
13
|
+
const facts = policies.schema[name];
|
|
14
|
+
const relations = facts?.relations ?? {};
|
|
15
|
+
return {
|
|
16
|
+
name,
|
|
17
|
+
foreign: facts?.foreign,
|
|
18
|
+
fields: (facts?.fields ?? [])
|
|
19
|
+
.filter((field) => relations[field] === undefined)
|
|
20
|
+
.sort(byCodeUnit),
|
|
21
|
+
relations: Object.keys(relations)
|
|
22
|
+
.sort(byCodeUnit)
|
|
23
|
+
.map((relation) => ({
|
|
24
|
+
name: relation,
|
|
25
|
+
target: relations[relation]?.target ?? "",
|
|
26
|
+
cardinality: relations[relation]?.cardinality ?? "one",
|
|
27
|
+
})),
|
|
28
|
+
};
|
|
29
|
+
}),
|
|
30
|
+
});
|
|
31
|
+
/** A property key as TypeScript writes it: bare when it is an identifier, quoted otherwise. */
|
|
32
|
+
export const propertyKey = (name) => /^[A-Za-z_$][\w$]*$/.test(name) ? name : JSON.stringify(name);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { AccessSchema } from "../access-schema.js";
|
|
2
|
+
import type { NamespaceFacts } from "./namespace.facts.js";
|
|
3
|
+
/** What `avaccess schema` read: the `AccessSchema`, and what it left out and why. */
|
|
4
|
+
export type OrmSchemaReading = {
|
|
5
|
+
readonly schema: AccessSchema;
|
|
6
|
+
readonly skipped: readonly string[];
|
|
7
|
+
};
|
|
8
|
+
/** The typed functions a translator adds to the generated client. */
|
|
9
|
+
export type OrmClientPart = {
|
|
10
|
+
/** Their declarations, in TypeScript. */
|
|
11
|
+
readonly text: string;
|
|
12
|
+
/** The names they add to the generated `access` object, in order. */
|
|
13
|
+
readonly members: readonly string[];
|
|
14
|
+
/** What they read from the translator's copied module, in the internal file. */
|
|
15
|
+
readonly imports: {
|
|
16
|
+
readonly values: readonly string[];
|
|
17
|
+
readonly types: readonly string[];
|
|
18
|
+
};
|
|
19
|
+
/** The copied module's types the client file re-exports. */
|
|
20
|
+
readonly exports: readonly string[];
|
|
21
|
+
};
|
|
22
|
+
/** What `avaccess generate` reads of a translator: `none`, or an ORM's. */
|
|
23
|
+
export type ClientTranslator = {
|
|
24
|
+
/** The `--orm` value: `none`, or the ORM and its major, `prisma7`. */
|
|
25
|
+
readonly orm: string;
|
|
26
|
+
/** The ORM's name and major as a reader says them, `Prisma 7`; `undefined` for `none`. */
|
|
27
|
+
readonly title: string | undefined;
|
|
28
|
+
/** The package paths of the translator's own modules, copied after the decisions. */
|
|
29
|
+
readonly modules: readonly string[];
|
|
30
|
+
/** The functions the generated client adds for this ORM. */
|
|
31
|
+
clientPart(namespace: NamespaceFacts): OrmClientPart;
|
|
32
|
+
};
|
|
33
|
+
/** One ORM's translator: its client part, and its schema reader. */
|
|
34
|
+
export type OrmTranslator = ClientTranslator & {
|
|
35
|
+
readonly title: string;
|
|
36
|
+
/** The schema `avaccess schema` reads when `--schema` is not given, from the project's root. */
|
|
37
|
+
readonly defaultSchema: string;
|
|
38
|
+
/** `avaccess schema`: the ORM's schema at `path` as an `AccessSchema`. */
|
|
39
|
+
readSchema(path: string): Promise<OrmSchemaReading>;
|
|
40
|
+
};
|
|
41
|
+
/** Every ORM translator, by its `--orm` value: what `avaccess schema` reads with. */
|
|
42
|
+
export declare const ORM_TRANSLATORS: {
|
|
43
|
+
readonly [orm: string]: OrmTranslator;
|
|
44
|
+
};
|
|
45
|
+
/** Every translator `avaccess generate` takes, by its `--orm` value. */
|
|
46
|
+
export declare const CLIENT_TRANSLATORS: {
|
|
47
|
+
readonly [orm: string]: ClientTranslator;
|
|
48
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// The translator seam: one translator per ORM major, chosen with `--orm`. A client
|
|
2
|
+
// translator gives `avaccess generate` the modules it copies after the decisions and
|
|
3
|
+
// the typed functions the generated client adds for its ORM; an ORM translator also
|
|
4
|
+
// gives `avaccess schema` the reader that turns its ORM's schema into an
|
|
5
|
+
// `AccessSchema`. The decisions stay ORM-neutral: they answer in Aventara's `where`,
|
|
6
|
+
// and only a translator speaks an ORM's words.
|
|
7
|
+
//
|
|
8
|
+
// `none` (the default for `generate`, ruled 2026-10-23) adds nothing: the client
|
|
9
|
+
// answers in the neutral `where` and names no ORM. Prisma 7 is the first ORM
|
|
10
|
+
// (`prisma7`). Drizzle follows as `drizzle1` once Drizzle ORM v1 is stable.
|
|
11
|
+
import { prisma7Translator } from "./prisma7/prisma7.translator.js";
|
|
12
|
+
/** Every ORM translator, by its `--orm` value: what `avaccess schema` reads with. */
|
|
13
|
+
export const ORM_TRANSLATORS = {
|
|
14
|
+
prisma7: prisma7Translator,
|
|
15
|
+
};
|
|
16
|
+
/** `--orm none`: a client that answers in the neutral `where` and names no ORM. */
|
|
17
|
+
const NO_TRANSLATOR = {
|
|
18
|
+
orm: "none",
|
|
19
|
+
title: undefined,
|
|
20
|
+
modules: [],
|
|
21
|
+
clientPart: () => ({
|
|
22
|
+
text: "",
|
|
23
|
+
members: [],
|
|
24
|
+
imports: { values: [], types: [] },
|
|
25
|
+
exports: [],
|
|
26
|
+
}),
|
|
27
|
+
};
|
|
28
|
+
/** Every translator `avaccess generate` takes, by its `--orm` value. */
|
|
29
|
+
export const CLIENT_TRANSLATORS = { none: NO_TRANSLATOR, ...ORM_TRANSLATORS };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AccessSchema } from "../../access-schema.js";
|
|
2
|
+
/** What the reader made of a schema: the `AccessSchema`, and what it left out and why. */
|
|
3
|
+
type PrismaSchemaReading = {
|
|
4
|
+
readonly schema: AccessSchema;
|
|
5
|
+
readonly skipped: readonly string[];
|
|
6
|
+
};
|
|
7
|
+
/** Reads the Prisma schema at `path` (a `.prisma` file or a folder of them) as an `AccessSchema`. */
|
|
8
|
+
export declare const readPrismaSchema: (path: string) => Promise<PrismaSchemaReading>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
// A Prisma 7 schema (`schema.prisma`, or a folder of `.prisma` files) read as the
|
|
2
|
+
// `AccessSchema` a service authors its rules against with `definePolicies`. It reads
|
|
3
|
+
// what the Aventara framework's Prisma 7 discovery reads for the same facts, so an
|
|
4
|
+
// Aventara app's discovered model and this reader agree on every Resource: each
|
|
5
|
+
// model's scalar and relation fields, enums, the reference pairs a relation holds,
|
|
6
|
+
// its inverse, and the field tuples that identify a row.
|
|
7
|
+
//
|
|
8
|
+
// It is a bounded reader, not a parser: Prisma's schema language puts each field and
|
|
9
|
+
// each block attribute on one line of its own (a declaration split over lines is a
|
|
10
|
+
// Prisma validation error), so it reads line by line. It locates tokens and never
|
|
11
|
+
// evaluates them: `@default(...)`, `@map`, `@db.*`, `@@index` and `@@schema` are
|
|
12
|
+
// read past. What it cannot model (an `Unsupported(...)` column, a composite `type`,
|
|
13
|
+
// a `view`, an `@ignore`d field or model) is left out and reported, never guessed.
|
|
14
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
15
|
+
import { resolve } from "node:path";
|
|
16
|
+
import { BEACON_TABLE } from "../../beacon/beacon.store.js";
|
|
17
|
+
/** Prisma's built-in scalars, as Access (and the framework) name them. */
|
|
18
|
+
const SCALARS = {
|
|
19
|
+
String: "string",
|
|
20
|
+
Boolean: "boolean",
|
|
21
|
+
Int: "int",
|
|
22
|
+
Float: "float",
|
|
23
|
+
BigInt: "bigint",
|
|
24
|
+
Decimal: "decimal",
|
|
25
|
+
DateTime: "datetime",
|
|
26
|
+
Bytes: "bytes",
|
|
27
|
+
Json: "json",
|
|
28
|
+
};
|
|
29
|
+
/** A line without its comment: `//` outside a string literal ends the line. */
|
|
30
|
+
const withoutComment = (line) => {
|
|
31
|
+
let quoted = false;
|
|
32
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
33
|
+
const char = line[index];
|
|
34
|
+
if (char === "\\" && quoted) {
|
|
35
|
+
index += 1;
|
|
36
|
+
}
|
|
37
|
+
else if (char === '"') {
|
|
38
|
+
quoted = !quoted;
|
|
39
|
+
}
|
|
40
|
+
else if (!quoted && char === "/" && line[index + 1] === "/") {
|
|
41
|
+
return line.slice(0, index);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return line;
|
|
45
|
+
};
|
|
46
|
+
/** The `@name(args)` and `@@name(args)` attributes of a line, in order, with their raw arguments. */
|
|
47
|
+
const attributesOf = (text) => {
|
|
48
|
+
const attributes = [];
|
|
49
|
+
let index = 0;
|
|
50
|
+
while (index < text.length) {
|
|
51
|
+
if (text[index] !== "@") {
|
|
52
|
+
index += 1;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const start = index;
|
|
56
|
+
while (text[index] === "@") {
|
|
57
|
+
index += 1;
|
|
58
|
+
}
|
|
59
|
+
const nameMatch = /^[A-Za-z_][\w.]*/.exec(text.slice(index));
|
|
60
|
+
const name = `${text.slice(start, index)}${nameMatch?.[0] ?? ""}`;
|
|
61
|
+
index += nameMatch?.[0].length ?? 0;
|
|
62
|
+
let args;
|
|
63
|
+
if (text[index] === "(") {
|
|
64
|
+
let depth = 0;
|
|
65
|
+
let quoted = false;
|
|
66
|
+
const open = index;
|
|
67
|
+
for (; index < text.length; index += 1) {
|
|
68
|
+
const char = text[index];
|
|
69
|
+
if (quoted) {
|
|
70
|
+
if (char === "\\") {
|
|
71
|
+
index += 1;
|
|
72
|
+
}
|
|
73
|
+
else if (char === '"') {
|
|
74
|
+
quoted = false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else if (char === '"') {
|
|
78
|
+
quoted = true;
|
|
79
|
+
}
|
|
80
|
+
else if (char === "(") {
|
|
81
|
+
depth += 1;
|
|
82
|
+
}
|
|
83
|
+
else if (char === ")") {
|
|
84
|
+
depth -= 1;
|
|
85
|
+
if (depth === 0) {
|
|
86
|
+
index += 1;
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
args = text.slice(open + 1, index - 1);
|
|
92
|
+
}
|
|
93
|
+
attributes.push({ name, args });
|
|
94
|
+
}
|
|
95
|
+
return attributes;
|
|
96
|
+
};
|
|
97
|
+
/** An attribute's arguments split at the commas outside brackets, parentheses and strings. */
|
|
98
|
+
const argumentsOf = (args) => {
|
|
99
|
+
const parts = [];
|
|
100
|
+
let depth = 0;
|
|
101
|
+
let quoted = false;
|
|
102
|
+
let current = "";
|
|
103
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
104
|
+
const char = args[index] ?? "";
|
|
105
|
+
if (quoted) {
|
|
106
|
+
current += char;
|
|
107
|
+
if (char === "\\") {
|
|
108
|
+
current += args[index + 1] ?? "";
|
|
109
|
+
index += 1;
|
|
110
|
+
}
|
|
111
|
+
else if (char === '"') {
|
|
112
|
+
quoted = false;
|
|
113
|
+
}
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (char === '"') {
|
|
117
|
+
quoted = true;
|
|
118
|
+
}
|
|
119
|
+
else if (char === "(" || char === "[") {
|
|
120
|
+
depth += 1;
|
|
121
|
+
}
|
|
122
|
+
else if (char === ")" || char === "]") {
|
|
123
|
+
depth -= 1;
|
|
124
|
+
}
|
|
125
|
+
else if (char === "," && depth === 0) {
|
|
126
|
+
parts.push(current.trim());
|
|
127
|
+
current = "";
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
current += char;
|
|
131
|
+
}
|
|
132
|
+
if (current.trim() !== "") {
|
|
133
|
+
parts.push(current.trim());
|
|
134
|
+
}
|
|
135
|
+
return parts;
|
|
136
|
+
};
|
|
137
|
+
/** The named argument `name:` of an attribute, or its first positional one when `name` is `undefined`. */
|
|
138
|
+
const argumentOf = (args, name) => {
|
|
139
|
+
for (const part of argumentsOf(args ?? "")) {
|
|
140
|
+
const named = /^([A-Za-z_]\w*)\s*:\s*([\s\S]*)$/.exec(part);
|
|
141
|
+
if (name === undefined ? named === null : named?.[1] === name) {
|
|
142
|
+
return name === undefined ? part : named?.[2]?.trim();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return undefined;
|
|
146
|
+
};
|
|
147
|
+
/** The field names of a `[a, b(sort: Desc)]` list. */
|
|
148
|
+
const fieldListOf = (list) => {
|
|
149
|
+
const inner = /^\[([\s\S]*)\]$/.exec(list?.trim() ?? "")?.[1];
|
|
150
|
+
if (inner === undefined) {
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
return argumentsOf(inner)
|
|
154
|
+
.map((member) => /^[A-Za-z_]\w*/.exec(member)?.[0] ?? "")
|
|
155
|
+
.filter((member) => member !== "");
|
|
156
|
+
};
|
|
157
|
+
/** A string literal's value: `"Mentorship"` → `Mentorship`. */
|
|
158
|
+
const stringOf = (literal) => /^"((?:[^"\\]|\\.)*)"$/.exec(literal?.trim() ?? "")?.[1];
|
|
159
|
+
const FIELD = /^([A-Za-z_]\w*)\s+([A-Za-z_]\w*(?:\([^)]*\))?)(\[\])?(\?)?(.*)$/;
|
|
160
|
+
/** The `.prisma` files at `path`: the file itself, or every one under the folder, by path. */
|
|
161
|
+
const schemaFiles = async (path) => {
|
|
162
|
+
if (path.endsWith(".prisma")) {
|
|
163
|
+
return [path];
|
|
164
|
+
}
|
|
165
|
+
const files = [];
|
|
166
|
+
const walk = async (folder) => {
|
|
167
|
+
const entries = await readdir(folder, { withFileTypes: true });
|
|
168
|
+
for (const entry of entries) {
|
|
169
|
+
const full = resolve(folder, entry.name);
|
|
170
|
+
if (entry.isDirectory()) {
|
|
171
|
+
await walk(full);
|
|
172
|
+
}
|
|
173
|
+
else if (entry.isFile() && entry.name.endsWith(".prisma")) {
|
|
174
|
+
files.push(full);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
await walk(path);
|
|
179
|
+
return files.sort();
|
|
180
|
+
};
|
|
181
|
+
/** Reads the schema's blocks: models with their lines, enums with their values. */
|
|
182
|
+
const blocksOf = (sources, skipped) => {
|
|
183
|
+
const models = [];
|
|
184
|
+
const enums = new Map();
|
|
185
|
+
const composites = new Set();
|
|
186
|
+
for (const { file, text } of sources) {
|
|
187
|
+
let block;
|
|
188
|
+
for (const raw of text.split(/\r?\n/)) {
|
|
189
|
+
const line = withoutComment(raw).trim();
|
|
190
|
+
if (line === "") {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (block === undefined) {
|
|
194
|
+
const opened = /^(\w+)\s+([A-Za-z_]\w*)\s*\{$/.exec(line);
|
|
195
|
+
if (opened !== null) {
|
|
196
|
+
block = { kind: opened[1] ?? "", name: opened[2] ?? "", lines: [] };
|
|
197
|
+
}
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (line === "}") {
|
|
201
|
+
if (block.kind === "model") {
|
|
202
|
+
const fields = [];
|
|
203
|
+
const blockAttributes = [];
|
|
204
|
+
for (const member of block.lines) {
|
|
205
|
+
if (member.startsWith("@@")) {
|
|
206
|
+
blockAttributes.push(...attributesOf(member));
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
const field = FIELD.exec(member);
|
|
210
|
+
if (field === null) {
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
fields.push({
|
|
214
|
+
name: field[1] ?? "",
|
|
215
|
+
type: field[2] ?? "",
|
|
216
|
+
list: field[3] !== undefined,
|
|
217
|
+
optional: field[4] !== undefined,
|
|
218
|
+
attributes: attributesOf(field[5] ?? ""),
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
models.push({ name: block.name, file, fields, blockAttributes });
|
|
222
|
+
}
|
|
223
|
+
else if (block.kind === "enum") {
|
|
224
|
+
enums.set(block.name, block.lines
|
|
225
|
+
.filter((member) => !member.startsWith("@@"))
|
|
226
|
+
.map((member) => /^[A-Za-z_]\w*/.exec(member)?.[0] ?? "")
|
|
227
|
+
.filter((member) => member !== ""));
|
|
228
|
+
}
|
|
229
|
+
else if (block.kind === "type") {
|
|
230
|
+
composites.add(block.name);
|
|
231
|
+
}
|
|
232
|
+
else if (block.kind === "view") {
|
|
233
|
+
skipped.push(`view ${block.name}: a view is not a Resource Access reads; left out`);
|
|
234
|
+
}
|
|
235
|
+
block = undefined;
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
block.lines.push(line);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return { models, enums, composites };
|
|
242
|
+
};
|
|
243
|
+
const has = (attributes, name) => attributes.some((attribute) => attribute.name === name);
|
|
244
|
+
/** The relation's name, from `@relation("Name")` or `@relation(name: "Name")`. */
|
|
245
|
+
const relationNameOf = (field) => {
|
|
246
|
+
const relation = field.attributes.find((attribute) => attribute.name === "@relation");
|
|
247
|
+
if (relation === undefined) {
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
return (stringOf(argumentOf(relation.args, "name")) ??
|
|
251
|
+
stringOf(argumentOf(relation.args, undefined)) ??
|
|
252
|
+
null);
|
|
253
|
+
};
|
|
254
|
+
/** Whether a model is the ownership beacon's table: named, or mapped to, `_aventara_beacon`. */
|
|
255
|
+
const isBeaconTable = (model) => BEACON_NAMES.includes(model.name) ||
|
|
256
|
+
model.blockAttributes.some((attribute) => attribute.name === "@@map" &&
|
|
257
|
+
BEACON_NAMES.includes(stringOf(argumentOf(attribute.args, undefined) ??
|
|
258
|
+
argumentOf(attribute.args, "name")) ?? ""));
|
|
259
|
+
/** The beacon table's names: a service's `_aventara_beacon`, the Access server's `aventaraBeacon` (Prisma model `AventaraBeacon`). */
|
|
260
|
+
const BEACON_NAMES = [
|
|
261
|
+
BEACON_TABLE,
|
|
262
|
+
"aventaraBeacon",
|
|
263
|
+
"AventaraBeacon",
|
|
264
|
+
];
|
|
265
|
+
/** Reads the Prisma schema at `path` (a `.prisma` file or a folder of them) as an `AccessSchema`. */
|
|
266
|
+
export const readPrismaSchema = async (path) => {
|
|
267
|
+
const sources = await Promise.all((await schemaFiles(path)).map(async (file) => ({
|
|
268
|
+
file,
|
|
269
|
+
text: await readFile(file, "utf8"),
|
|
270
|
+
})));
|
|
271
|
+
const skipped = [];
|
|
272
|
+
const { models: declared, enums, composites } = blocksOf(sources, skipped);
|
|
273
|
+
const models = declared.filter((model) => {
|
|
274
|
+
if (has(model.blockAttributes, "@@ignore")) {
|
|
275
|
+
skipped.push(`model ${model.name}: @@ignore; left out`);
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
if (isBeaconTable(model)) {
|
|
279
|
+
skipped.push(`model ${model.name}: the ownership beacon's table, which no rule reads; left out`);
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
return true;
|
|
283
|
+
});
|
|
284
|
+
const byName = new Map(models.map((model) => [model.name, model]));
|
|
285
|
+
const ignoredModels = new Set(declared.filter((model) => !byName.has(model.name)).map((m) => m.name));
|
|
286
|
+
const resources = {};
|
|
287
|
+
for (const model of models) {
|
|
288
|
+
const fields = {};
|
|
289
|
+
const columns = new Map();
|
|
290
|
+
for (const field of model.fields) {
|
|
291
|
+
const where = `${model.name}.${field.name}`;
|
|
292
|
+
if (has(field.attributes, "@ignore")) {
|
|
293
|
+
skipped.push(`${where}: @ignore; left out`);
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
const scalar = SCALARS[field.type];
|
|
297
|
+
if (scalar !== undefined || enums.has(field.type)) {
|
|
298
|
+
fields[field.name] = {
|
|
299
|
+
kind: "scalar",
|
|
300
|
+
type: scalar !== undefined ? { scalar } : { enum: field.type },
|
|
301
|
+
nullable: field.optional,
|
|
302
|
+
list: field.list,
|
|
303
|
+
};
|
|
304
|
+
if (!field.list) {
|
|
305
|
+
columns.set(field.name, field);
|
|
306
|
+
}
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
const target = byName.get(field.type);
|
|
310
|
+
if (target === undefined) {
|
|
311
|
+
skipped.push(`${where}: ${field.type.startsWith("Unsupported(")
|
|
312
|
+
? "an Unsupported column"
|
|
313
|
+
: composites.has(field.type)
|
|
314
|
+
? `the composite type ${field.type}`
|
|
315
|
+
: ignoredModels.has(field.type)
|
|
316
|
+
? `a relation to the ignored model ${field.type}`
|
|
317
|
+
: `the type ${field.type}, which the schema does not declare`}; left out`);
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
const name = relationNameOf(field);
|
|
321
|
+
const partners = target.fields.filter((candidate) => candidate.type === model.name &&
|
|
322
|
+
relationNameOf(candidate) === name &&
|
|
323
|
+
!(target.name === model.name && candidate.name === field.name));
|
|
324
|
+
const relation = field.attributes.find((attribute) => attribute.name === "@relation");
|
|
325
|
+
const referenceFields = fieldListOf(argumentOf(relation?.args, "fields"));
|
|
326
|
+
const references = fieldListOf(argumentOf(relation?.args, "references"));
|
|
327
|
+
const cardinality = field.list ? "many" : "one";
|
|
328
|
+
const fact = {
|
|
329
|
+
kind: "relation",
|
|
330
|
+
target: target.name,
|
|
331
|
+
cardinality,
|
|
332
|
+
nullable: cardinality === "one" && field.optional,
|
|
333
|
+
...(partners.length === 1 && partners[0] !== undefined
|
|
334
|
+
? { inverse: partners[0].name }
|
|
335
|
+
: {}),
|
|
336
|
+
...(referenceFields !== undefined &&
|
|
337
|
+
referenceFields.length > 0 &&
|
|
338
|
+
references !== undefined &&
|
|
339
|
+
references.length > 0
|
|
340
|
+
? {
|
|
341
|
+
referenceFields: referenceFields,
|
|
342
|
+
references: references,
|
|
343
|
+
}
|
|
344
|
+
: {}),
|
|
345
|
+
};
|
|
346
|
+
fields[field.name] = fact;
|
|
347
|
+
}
|
|
348
|
+
// Identifiers, as discovery lists them: each field's `@id` then `@unique`, in
|
|
349
|
+
// field order, then `@@id`, then each `@@unique`; a tuple once; none over a
|
|
350
|
+
// field that is not a column here, and none over a nullable one.
|
|
351
|
+
const criteria = [];
|
|
352
|
+
for (const field of model.fields) {
|
|
353
|
+
if (has(field.attributes, "@id")) {
|
|
354
|
+
criteria.push([field.name]);
|
|
355
|
+
}
|
|
356
|
+
if (has(field.attributes, "@unique")) {
|
|
357
|
+
criteria.push([field.name]);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
for (const name of ["@@id", "@@unique"]) {
|
|
361
|
+
for (const attribute of model.blockAttributes) {
|
|
362
|
+
if (attribute.name !== name) {
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
const members = fieldListOf(argumentOf(attribute.args, "fields")) ??
|
|
366
|
+
fieldListOf(argumentOf(attribute.args, undefined));
|
|
367
|
+
if (members !== undefined) {
|
|
368
|
+
criteria.push(members);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
const seen = new Set();
|
|
373
|
+
const identifiers = [];
|
|
374
|
+
for (const members of criteria) {
|
|
375
|
+
const key = JSON.stringify(members);
|
|
376
|
+
if (seen.has(key)) {
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
seen.add(key);
|
|
380
|
+
if (members.length > 0 &&
|
|
381
|
+
members.every((member) => columns.get(member)?.optional === false)) {
|
|
382
|
+
identifiers.push(members);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
resources[model.name] = { fields, identifiers };
|
|
386
|
+
}
|
|
387
|
+
return {
|
|
388
|
+
schema: {
|
|
389
|
+
enums: Object.fromEntries([...enums].map(([name, values]) => [name, { values }])),
|
|
390
|
+
resources,
|
|
391
|
+
},
|
|
392
|
+
skipped,
|
|
393
|
+
};
|
|
394
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { type AccessWhere } from "../../aventara-where.translator.js";
|
|
2
|
+
import type { AccessFields } from "../../policies.decider.js";
|
|
3
|
+
import type { AccessPolicies } from "../../policies-contract.js";
|
|
4
|
+
/** A Prisma `where`: plain data any `<Model>WhereInput` accepts. */
|
|
5
|
+
export type PrismaWhere = {
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
};
|
|
8
|
+
/** A Prisma `select` of scalar fields. */
|
|
9
|
+
export type PrismaSelect = {
|
|
10
|
+
[field: string]: true;
|
|
11
|
+
};
|
|
12
|
+
/** What `prismaExists` needs of a model's delegate on the Prisma client. */
|
|
13
|
+
export type PrismaFindFirst = {
|
|
14
|
+
findFirst(args: {
|
|
15
|
+
where: PrismaWhere;
|
|
16
|
+
select: PrismaSelect;
|
|
17
|
+
}): PromiseLike<unknown>;
|
|
18
|
+
};
|
|
19
|
+
/** Aventara's `where` on a Resource of `policies`, as Prisma's `where` on its model. */
|
|
20
|
+
export declare const toPrismaWhere: (policies: AccessPolicies, resource: string, where: AccessWhere) => PrismaWhere;
|
|
21
|
+
/**
|
|
22
|
+
* A scope (`scopeOf`'s answer) as Prisma's `where`: every row (`{}`), no row
|
|
23
|
+
* (`{ OR: [] }`, which Prisma matches with nothing), or the translated condition.
|
|
24
|
+
*/
|
|
25
|
+
export declare const toPrismaScope: (policies: AccessPolicies, resource: string, scope: boolean | AccessWhere) => PrismaWhere;
|
|
26
|
+
/**
|
|
27
|
+
* A `fieldsOf` read answer as Prisma's `select`: the Resource's scalar fields a read
|
|
28
|
+
* shows on every row. A field governed for reading is selected only when the answer
|
|
29
|
+
* opens it on every row (one governed for writing only is read as any other); a
|
|
30
|
+
* field it opens on some rows only is left out, since a `select` cannot depend on
|
|
31
|
+
* the row (ask `fieldsOf` for those). Relations are never selected: a related row
|
|
32
|
+
* would not be scoped.
|
|
33
|
+
*/
|
|
34
|
+
export declare const toPrismaSelect: (policies: AccessPolicies, resource: string, fields: AccessFields) => PrismaSelect;
|
|
35
|
+
/** The property of the Prisma client that holds a model's delegate: its name, first letter lowered. */
|
|
36
|
+
export declare const prismaDelegateOf: (resource: string) => string;
|
|
37
|
+
/**
|
|
38
|
+
* Core's `exists`, through the service's Prisma client: whether a row of `resource`
|
|
39
|
+
* meets `where`, unscoped. It selects the row's first identifier and nothing else.
|
|
40
|
+
*/
|
|
41
|
+
export declare const existsThroughPrisma: (client: object, policies: AccessPolicies, resource: string, where: AccessWhere) => Promise<boolean>;
|
|
42
|
+
/**
|
|
43
|
+
* The Prisma client the ownership beacon is read and written through: a model over
|
|
44
|
+
* the `_aventara_beacon` table, keyed by the namespace,
|
|
45
|
+
* `model AventaraBeacon { id String @id namespace String @unique value String createdAt DateTime @default(now()) @@map("_aventara_beacon") }`.
|
|
46
|
+
*/
|
|
47
|
+
export type PrismaBeaconClient = {
|
|
48
|
+
readonly aventaraBeacon: {
|
|
49
|
+
findUnique(args: {
|
|
50
|
+
where: {
|
|
51
|
+
namespace: string;
|
|
52
|
+
};
|
|
53
|
+
select: {
|
|
54
|
+
value: true;
|
|
55
|
+
};
|
|
56
|
+
}): PromiseLike<unknown>;
|
|
57
|
+
create(args: {
|
|
58
|
+
data: {
|
|
59
|
+
namespace: string;
|
|
60
|
+
value: string;
|
|
61
|
+
};
|
|
62
|
+
}): PromiseLike<unknown>;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* The beacon store over the service's Prisma client: `read` a namespace's row in
|
|
67
|
+
* `_aventara_beacon`, `create` one. What `avaccess push --beacon` and `pull --beacon`
|
|
68
|
+
* load, and what the client's `checkBeacons` reads through.
|
|
69
|
+
*/
|
|
70
|
+
export declare const beaconThroughPrisma: (client: PrismaBeaconClient) => {
|
|
71
|
+
read(namespace: string): Promise<string | null>;
|
|
72
|
+
create(namespace: string, value: string): Promise<void>;
|
|
73
|
+
};
|