@maravilla-labs/platform 0.3.3 → 0.3.7
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/config.d.ts +30 -1
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +287 -1
- package/dist/index.js +287 -40
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/config.ts +40 -0
- package/src/index.ts +7 -1
- package/src/media.ts +2 -1
- package/src/remote-client.ts +268 -43
- package/src/ren.ts +8 -1
- package/src/request-scope.ts +133 -0
- package/src/types.ts +293 -0
package/dist/config.d.ts
CHANGED
|
@@ -42,6 +42,16 @@ type SecretRef = string | {
|
|
|
42
42
|
env: string;
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* The platform service this resource binds to. Used by the UI to offer
|
|
47
|
+
* service-correct action presets and policy snippets, and by the reconciler
|
|
48
|
+
* to validate that policies reference legal `node.*` fields for the service.
|
|
49
|
+
*
|
|
50
|
+
* Omit for legacy / cross-service umbrella resources — the runtime falls back
|
|
51
|
+
* to matching purely by `name` (a name collision between e.g. a KV namespace
|
|
52
|
+
* and a DB collection will silently share a policy, which is rarely desired).
|
|
53
|
+
*/
|
|
54
|
+
type ResourceServiceType = 'kv' | 'database' | 'realtime' | 'media' | 'vector' | 'storage' | 'queue' | 'push' | 'workflow' | 'transforms';
|
|
45
55
|
interface ResourceDefinition {
|
|
46
56
|
/** URL-safe slug. Used as the resource key in code (e.g. the KV namespace). */
|
|
47
57
|
name: string;
|
|
@@ -49,6 +59,12 @@ interface ResourceDefinition {
|
|
|
49
59
|
title: string;
|
|
50
60
|
/** Optional longer description. */
|
|
51
61
|
description?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Which platform service this resource gates. When set, the reconciler
|
|
64
|
+
* validates that the policy only references `node.*` fields legal for that
|
|
65
|
+
* service (e.g. a `realtime` policy can't reference `node.collection`).
|
|
66
|
+
*/
|
|
67
|
+
type?: ResourceServiceType;
|
|
52
68
|
/** Actions this resource supports, e.g. `['read', 'write', 'delete']`. */
|
|
53
69
|
actions: string[];
|
|
54
70
|
/**
|
|
@@ -57,6 +73,19 @@ interface ResourceDefinition {
|
|
|
57
73
|
* Layer 2 for this resource — tenant + owner isolation still applies.
|
|
58
74
|
*/
|
|
59
75
|
policy?: string;
|
|
76
|
+
/**
|
|
77
|
+
* C+D read-filter (option ii). JSON object the runtime ANDs into the
|
|
78
|
+
* caller's filter on `db.find` / `db.findOne`. Supports `$auth.<path>`
|
|
79
|
+
* placeholder strings (e.g. `"$auth.user_id"`) substituted from the
|
|
80
|
+
* caller's identity at request time. Allowed paths: `user_id`, `email`,
|
|
81
|
+
* `is_admin`, `roles`.
|
|
82
|
+
*
|
|
83
|
+
* Independent of `policy` — `policy` gates writes and resolved-doc reads;
|
|
84
|
+
* `read_filter` scopes which rows the caller can ever see.
|
|
85
|
+
*
|
|
86
|
+
* Example: `'{"$or":[{"owner":"$auth.user_id"},{"public":true}]}'`
|
|
87
|
+
*/
|
|
88
|
+
read_filter?: string;
|
|
60
89
|
}
|
|
61
90
|
interface GroupPermissionDefinition {
|
|
62
91
|
/** Must match a `ResourceDefinition.name`. */
|
|
@@ -244,4 +273,4 @@ interface DatabaseConfigBlock {
|
|
|
244
273
|
*/
|
|
245
274
|
declare function defineConfig(config: MaravillaConfig): MaravillaConfig;
|
|
246
275
|
|
|
247
|
-
export { type AuthConfigBlock, type BrandingConfig, type DatabaseConfigBlock, type DocumentIndexDeclaration, type GroupDefinition, type GroupPermissionDefinition, type IndexDirectionConfig, type MaravillaConfig, type OAuthProviderDefinition, type OAuthProvidersConfig, type PasswordPolicyDefinition, type RegistrationConfig, type RegistrationFieldDefinition, type RelationTypeDefinition, type ResourceDefinition, type SecretRef, type SecurityConfig, type SessionConfigDefinition, TransformsConfig, type VectorIndexDeclaration, type VectorMetricConfig, type VectorStorageConfig, defineConfig };
|
|
276
|
+
export { type AuthConfigBlock, type BrandingConfig, type DatabaseConfigBlock, type DocumentIndexDeclaration, type GroupDefinition, type GroupPermissionDefinition, type IndexDirectionConfig, type MaravillaConfig, type OAuthProviderDefinition, type OAuthProvidersConfig, type PasswordPolicyDefinition, type RegistrationConfig, type RegistrationFieldDefinition, type RelationTypeDefinition, type ResourceDefinition, type ResourceServiceType, type SecretRef, type SecurityConfig, type SessionConfigDefinition, TransformsConfig, type VectorIndexDeclaration, type VectorMetricConfig, type VectorStorageConfig, defineConfig };
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts"],"sourcesContent":["/**\n * @fileoverview Typed schema for `maravilla.config.{ts,yaml,json}` files.\n *\n * Declares your project's auth settings (resources, groups, relations,\n * registration fields, OAuth providers, security policy, branding) alongside\n * your code. The Maravilla adapter reads this at build time and reconciles\n * the settings into delivery on deploy.\n *\n * ```typescript\n * import { defineConfig } from '@maravilla-labs/platform/config';\n *\n * export default defineConfig({\n * auth: {\n * resources: [\n * { name: 'todos', title: 'Todos', actions: ['read', 'write'],\n * policy: 'auth.user_id == node.owner' },\n * ],\n * },\n * });\n * ```\n *\n * Omitted sections leave the DB alone — partial adoption is explicitly\n * supported. List-based sections (`resources`, `groups`, `relations`,\n * `oauth`) are upserted and never auto-delete DB-only entries. Singleton\n * sections (`registration`, `security`, `branding`) are replaced wholesale\n * when declared.\n */\n\n/**\n * String value that may either be a literal secret or a reference to an\n * environment variable on the **tenant** (resolved server-side at\n * reconcile time, never shipped plaintext in the manifest).\n *\n * Accepted forms:\n * - `\"literal-value\"` — inline (not recommended for real secrets)\n * - `\"${env.VAR_NAME}\"` — string-template form\n * - `{ env: \"VAR_NAME\" }` — object form\n */\nexport type SecretRef = string | { env: string };\n\nimport type { TransformsConfig } from './transforms.js';\nexport type { TransformsConfig, TransformsPatternSpec } from './transforms.js';\n\n// ── Resources + policies ──\n\nexport interface ResourceDefinition {\n /** URL-safe slug. Used as the resource key in code (e.g. the KV namespace). */\n name: string;\n /** Human-readable title for the admin UI. */\n title: string;\n /** Optional longer description. */\n description?: string;\n /** Actions this resource supports, e.g. `['read', 'write', 'delete']`. */\n actions: string[];\n /**\n * Optional raisin-rel policy expression. Evaluated on every KV/DB/\n * realtime/media op that targets this resource. Leave empty to skip\n * Layer 2 for this resource — tenant + owner isolation still applies.\n */\n policy?: string;\n}\n\n// ── Groups ──\n\nexport interface GroupPermissionDefinition {\n /** Must match a `ResourceDefinition.name`. */\n resource_name: string;\n /** Actions this group is granted on the resource. */\n actions: string[];\n}\n\nexport interface GroupDefinition {\n /** Unique group name per tenant. */\n name: string;\n /** Optional description for the admin UI. */\n description?: string;\n /** Resource permissions granted to the group. Replaces the group's current permissions when declared. */\n permissions?: GroupPermissionDefinition[];\n}\n\n// ── Relations ──\n\nexport interface RelationTypeDefinition {\n /** Uppercase identifier used in policies (`... VIA 'STEWARDS'`). */\n relation_name: string;\n /** Human-readable title. */\n title: string;\n description?: string;\n /** Grouping for the admin UI (e.g. `\"family\"`, `\"work\"`). */\n category?: string;\n icon?: string;\n color?: string;\n /** Name of the inverse relation type, if one exists. */\n inverse_relation_name?: string;\n /** When true, membership in this relation implies stewardship rights. */\n implies_stewardship?: boolean;\n /** When true, the relation can only target users flagged as minors. */\n requires_minor?: boolean;\n /** When true, the relation is symmetric (A→B implies B→A). */\n bidirectional?: boolean;\n}\n\n// ── Registration fields ──\n\nexport interface RegistrationFieldDefinition {\n /** Field key used as the form field name + in profile data. */\n key: string;\n /** Display label. */\n label: string;\n /** One of: text, email, phone, date, number, select, boolean, url, textarea. */\n field_type: string;\n required: boolean;\n show_on_register: boolean;\n /** Optional validation metadata — passed through to the UI. */\n validation?: Record<string, unknown>;\n}\n\nexport interface RegistrationConfig {\n /** Ordered list of custom registration fields. Declaring this replaces the full list. */\n fields: RegistrationFieldDefinition[];\n}\n\n// ── OAuth providers ──\n\nexport interface OAuthProviderDefinition {\n enabled: boolean;\n client_id: string;\n /** Prefer `{ env: \"VAR_NAME\" }` or `\"${env.VAR_NAME}\"`. */\n client_secret: SecretRef;\n scopes: string[];\n /** Only for `custom_oidc`. */\n discovery_url?: string;\n}\n\nexport interface OAuthProvidersConfig {\n google?: OAuthProviderDefinition;\n github?: OAuthProviderDefinition;\n okta?: OAuthProviderDefinition;\n custom_oidc?: OAuthProviderDefinition;\n}\n\n// ── Security ──\n\nexport interface PasswordPolicyDefinition {\n min_length: number;\n require_uppercase: boolean;\n require_number: boolean;\n require_special: boolean;\n}\n\nexport interface SessionConfigDefinition {\n access_token_ttl_secs: number;\n refresh_token_ttl_secs: number;\n max_sessions_per_user: number;\n require_email_verification: boolean;\n}\n\nexport interface SecurityConfig {\n password_policy?: PasswordPolicyDefinition;\n session?: SessionConfigDefinition;\n}\n\n// ── Branding ──\n\nexport interface BrandingConfig {\n app_name?: string;\n logo_url?: string;\n primary_color?: string;\n secondary_color?: string;\n welcome_message?: string;\n welcome_subtitle?: string;\n /** `\"centered\"`, `\"split-left\"`, `\"split-right\"`, or `\"fullscreen\"`. */\n layout?: string;\n background_image_url?: string;\n /** 0–100 percentage. */\n background_focal_point?: { x: number; y: number };\n background_gradient?: string;\n /** `\"light\"`, `\"dark\"`, or `\"auto\"`. */\n color_mode?: string;\n font_family?: string;\n terms_url?: string;\n privacy_url?: string;\n /** Raw CSS merged into the hosted auth pages. */\n custom_css?: string;\n}\n\n// ── Top-level shape ──\n\nexport interface AuthConfigBlock {\n resources?: ResourceDefinition[];\n groups?: GroupDefinition[];\n relations?: RelationTypeDefinition[];\n registration?: RegistrationConfig;\n oauth?: OAuthProvidersConfig;\n security?: SecurityConfig;\n branding?: BrandingConfig;\n}\n\nexport interface MaravillaConfig {\n /** All project-level auth settings. Every field is optional — partial adoption is supported. */\n auth?: AuthConfigBlock;\n /** Declarative database indexes (regular + vector). Reconciled upsert-only on deploy. */\n database?: DatabaseConfigBlock;\n /**\n * Declarative media transforms — each entry compiles into a synthetic\n * `storage.put` event handler that fans out the declared\n * `platform.media.transforms.*` calls (via `Promise.all`) for every\n * matching upload. See {@link TransformsConfig}.\n */\n transforms?: TransformsConfig;\n}\n\n// ── Database block ──\n//\n// Regular indexes speed up document reads on frequently-queried fields.\n// Vector indexes back hybrid semantic search via sqlite-vec. Both are\n// upsert-only — declaring an index in config creates it if missing,\n// updates metadata when safe, and never auto-deletes DB-only indexes.\n\n/** MongoDB-style key direction: `1` ascending, `-1` descending. */\nexport type IndexDirectionConfig = 1 | -1;\n\nexport interface DocumentIndexDeclaration {\n /** Collection the index lives on. */\n collection: string;\n /** Optional name; falls back to an auto-derived name. */\n name?: string;\n /**\n * Compound-index key shape. Array of `[field, direction]` tuples\n * preserves ordering, which matters for compound indexes.\n */\n keys: Array<[string, IndexDirectionConfig]> | Record<string, IndexDirectionConfig>;\n unique?: boolean;\n sparse?: boolean;\n /**\n * Partial-index predicate — restricted to inline-literal operators\n * (`$eq`, `$ne`, `$gt`/`$gte`/`$lt`/`$lte`, `$in`/`$nin`, `$exists`,\n * `$and`, `$or`). No `$regex` / `$where` / `$text`.\n */\n partial?: Record<string, unknown>;\n /** TTL in seconds. Requires a single-field index on a unix-seconds field. */\n expireAfterSeconds?: number;\n}\n\n/** Distance metric used by a vector index. */\nexport type VectorMetricConfig = 'cosine' | 'l2' | 'hamming';\n\n/** Storage precision for a vector index. */\nexport type VectorStorageConfig = 'float32' | 'int8' | 'bit';\n\nexport interface VectorIndexDeclaration {\n collection: string;\n field: string;\n dimensions: number;\n metric?: VectorMetricConfig;\n storage?: VectorStorageConfig;\n matryoshka?: boolean;\n multiVector?: boolean;\n}\n\nexport interface DatabaseConfigBlock {\n /** MongoDB-style secondary indexes. */\n indexes?: DocumentIndexDeclaration[];\n /** sqlite-vec-backed vector indexes. */\n vectorIndexes?: VectorIndexDeclaration[];\n}\n\n/**\n * Identity function that returns the config unchanged — exists purely so the\n * TypeScript compiler can infer `MaravillaConfig` and give you IntelliSense\n * on every field.\n *\n * @example\n * ```typescript\n * import { defineConfig } from '@maravilla-labs/platform/config';\n *\n * export default defineConfig({\n * auth: {\n * resources: [{ name: 'todos', title: 'Todos', actions: ['read', 'write'] }],\n * },\n * });\n * ```\n */\nexport function defineConfig(config: MaravillaConfig): MaravillaConfig {\n return config;\n}\n"],"mappings":";AA2RO,SAAS,aAAa,QAA0C;AACrE,SAAO;AACT;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/config.ts"],"sourcesContent":["/**\n * @fileoverview Typed schema for `maravilla.config.{ts,yaml,json}` files.\n *\n * Declares your project's auth settings (resources, groups, relations,\n * registration fields, OAuth providers, security policy, branding) alongside\n * your code. The Maravilla adapter reads this at build time and reconciles\n * the settings into delivery on deploy.\n *\n * ```typescript\n * import { defineConfig } from '@maravilla-labs/platform/config';\n *\n * export default defineConfig({\n * auth: {\n * resources: [\n * { name: 'todos', title: 'Todos', actions: ['read', 'write'],\n * policy: 'auth.user_id == node.owner' },\n * ],\n * },\n * });\n * ```\n *\n * Omitted sections leave the DB alone — partial adoption is explicitly\n * supported. List-based sections (`resources`, `groups`, `relations`,\n * `oauth`) are upserted and never auto-delete DB-only entries. Singleton\n * sections (`registration`, `security`, `branding`) are replaced wholesale\n * when declared.\n */\n\n/**\n * String value that may either be a literal secret or a reference to an\n * environment variable on the **tenant** (resolved server-side at\n * reconcile time, never shipped plaintext in the manifest).\n *\n * Accepted forms:\n * - `\"literal-value\"` — inline (not recommended for real secrets)\n * - `\"${env.VAR_NAME}\"` — string-template form\n * - `{ env: \"VAR_NAME\" }` — object form\n */\nexport type SecretRef = string | { env: string };\n\nimport type { TransformsConfig } from './transforms.js';\nexport type { TransformsConfig, TransformsPatternSpec } from './transforms.js';\n\n// ── Resources + policies ──\n\n/**\n * The platform service this resource binds to. Used by the UI to offer\n * service-correct action presets and policy snippets, and by the reconciler\n * to validate that policies reference legal `node.*` fields for the service.\n *\n * Omit for legacy / cross-service umbrella resources — the runtime falls back\n * to matching purely by `name` (a name collision between e.g. a KV namespace\n * and a DB collection will silently share a policy, which is rarely desired).\n */\nexport type ResourceServiceType =\n | 'kv'\n | 'database'\n | 'realtime'\n | 'media'\n | 'vector'\n | 'storage'\n | 'queue'\n | 'push'\n | 'workflow'\n | 'transforms';\n\nexport interface ResourceDefinition {\n /** URL-safe slug. Used as the resource key in code (e.g. the KV namespace). */\n name: string;\n /** Human-readable title for the admin UI. */\n title: string;\n /** Optional longer description. */\n description?: string;\n /**\n * Which platform service this resource gates. When set, the reconciler\n * validates that the policy only references `node.*` fields legal for that\n * service (e.g. a `realtime` policy can't reference `node.collection`).\n */\n type?: ResourceServiceType;\n /** Actions this resource supports, e.g. `['read', 'write', 'delete']`. */\n actions: string[];\n /**\n * Optional raisin-rel policy expression. Evaluated on every KV/DB/\n * realtime/media op that targets this resource. Leave empty to skip\n * Layer 2 for this resource — tenant + owner isolation still applies.\n */\n policy?: string;\n /**\n * C+D read-filter (option ii). JSON object the runtime ANDs into the\n * caller's filter on `db.find` / `db.findOne`. Supports `$auth.<path>`\n * placeholder strings (e.g. `\"$auth.user_id\"`) substituted from the\n * caller's identity at request time. Allowed paths: `user_id`, `email`,\n * `is_admin`, `roles`.\n *\n * Independent of `policy` — `policy` gates writes and resolved-doc reads;\n * `read_filter` scopes which rows the caller can ever see.\n *\n * Example: `'{\"$or\":[{\"owner\":\"$auth.user_id\"},{\"public\":true}]}'`\n */\n read_filter?: string;\n}\n\n// ── Groups ──\n\nexport interface GroupPermissionDefinition {\n /** Must match a `ResourceDefinition.name`. */\n resource_name: string;\n /** Actions this group is granted on the resource. */\n actions: string[];\n}\n\nexport interface GroupDefinition {\n /** Unique group name per tenant. */\n name: string;\n /** Optional description for the admin UI. */\n description?: string;\n /** Resource permissions granted to the group. Replaces the group's current permissions when declared. */\n permissions?: GroupPermissionDefinition[];\n}\n\n// ── Relations ──\n\nexport interface RelationTypeDefinition {\n /** Uppercase identifier used in policies (`... VIA 'STEWARDS'`). */\n relation_name: string;\n /** Human-readable title. */\n title: string;\n description?: string;\n /** Grouping for the admin UI (e.g. `\"family\"`, `\"work\"`). */\n category?: string;\n icon?: string;\n color?: string;\n /** Name of the inverse relation type, if one exists. */\n inverse_relation_name?: string;\n /** When true, membership in this relation implies stewardship rights. */\n implies_stewardship?: boolean;\n /** When true, the relation can only target users flagged as minors. */\n requires_minor?: boolean;\n /** When true, the relation is symmetric (A→B implies B→A). */\n bidirectional?: boolean;\n}\n\n// ── Registration fields ──\n\nexport interface RegistrationFieldDefinition {\n /** Field key used as the form field name + in profile data. */\n key: string;\n /** Display label. */\n label: string;\n /** One of: text, email, phone, date, number, select, boolean, url, textarea. */\n field_type: string;\n required: boolean;\n show_on_register: boolean;\n /** Optional validation metadata — passed through to the UI. */\n validation?: Record<string, unknown>;\n}\n\nexport interface RegistrationConfig {\n /** Ordered list of custom registration fields. Declaring this replaces the full list. */\n fields: RegistrationFieldDefinition[];\n}\n\n// ── OAuth providers ──\n\nexport interface OAuthProviderDefinition {\n enabled: boolean;\n client_id: string;\n /** Prefer `{ env: \"VAR_NAME\" }` or `\"${env.VAR_NAME}\"`. */\n client_secret: SecretRef;\n scopes: string[];\n /** Only for `custom_oidc`. */\n discovery_url?: string;\n}\n\nexport interface OAuthProvidersConfig {\n google?: OAuthProviderDefinition;\n github?: OAuthProviderDefinition;\n okta?: OAuthProviderDefinition;\n custom_oidc?: OAuthProviderDefinition;\n}\n\n// ── Security ──\n\nexport interface PasswordPolicyDefinition {\n min_length: number;\n require_uppercase: boolean;\n require_number: boolean;\n require_special: boolean;\n}\n\nexport interface SessionConfigDefinition {\n access_token_ttl_secs: number;\n refresh_token_ttl_secs: number;\n max_sessions_per_user: number;\n require_email_verification: boolean;\n}\n\nexport interface SecurityConfig {\n password_policy?: PasswordPolicyDefinition;\n session?: SessionConfigDefinition;\n}\n\n// ── Branding ──\n\nexport interface BrandingConfig {\n app_name?: string;\n logo_url?: string;\n primary_color?: string;\n secondary_color?: string;\n welcome_message?: string;\n welcome_subtitle?: string;\n /** `\"centered\"`, `\"split-left\"`, `\"split-right\"`, or `\"fullscreen\"`. */\n layout?: string;\n background_image_url?: string;\n /** 0–100 percentage. */\n background_focal_point?: { x: number; y: number };\n background_gradient?: string;\n /** `\"light\"`, `\"dark\"`, or `\"auto\"`. */\n color_mode?: string;\n font_family?: string;\n terms_url?: string;\n privacy_url?: string;\n /** Raw CSS merged into the hosted auth pages. */\n custom_css?: string;\n}\n\n// ── Top-level shape ──\n\nexport interface AuthConfigBlock {\n resources?: ResourceDefinition[];\n groups?: GroupDefinition[];\n relations?: RelationTypeDefinition[];\n registration?: RegistrationConfig;\n oauth?: OAuthProvidersConfig;\n security?: SecurityConfig;\n branding?: BrandingConfig;\n}\n\nexport interface MaravillaConfig {\n /** All project-level auth settings. Every field is optional — partial adoption is supported. */\n auth?: AuthConfigBlock;\n /** Declarative database indexes (regular + vector). Reconciled upsert-only on deploy. */\n database?: DatabaseConfigBlock;\n /**\n * Declarative media transforms — each entry compiles into a synthetic\n * `storage.put` event handler that fans out the declared\n * `platform.media.transforms.*` calls (via `Promise.all`) for every\n * matching upload. See {@link TransformsConfig}.\n */\n transforms?: TransformsConfig;\n}\n\n// ── Database block ──\n//\n// Regular indexes speed up document reads on frequently-queried fields.\n// Vector indexes back hybrid semantic search via sqlite-vec. Both are\n// upsert-only — declaring an index in config creates it if missing,\n// updates metadata when safe, and never auto-deletes DB-only indexes.\n\n/** MongoDB-style key direction: `1` ascending, `-1` descending. */\nexport type IndexDirectionConfig = 1 | -1;\n\nexport interface DocumentIndexDeclaration {\n /** Collection the index lives on. */\n collection: string;\n /** Optional name; falls back to an auto-derived name. */\n name?: string;\n /**\n * Compound-index key shape. Array of `[field, direction]` tuples\n * preserves ordering, which matters for compound indexes.\n */\n keys: Array<[string, IndexDirectionConfig]> | Record<string, IndexDirectionConfig>;\n unique?: boolean;\n sparse?: boolean;\n /**\n * Partial-index predicate — restricted to inline-literal operators\n * (`$eq`, `$ne`, `$gt`/`$gte`/`$lt`/`$lte`, `$in`/`$nin`, `$exists`,\n * `$and`, `$or`). No `$regex` / `$where` / `$text`.\n */\n partial?: Record<string, unknown>;\n /** TTL in seconds. Requires a single-field index on a unix-seconds field. */\n expireAfterSeconds?: number;\n}\n\n/** Distance metric used by a vector index. */\nexport type VectorMetricConfig = 'cosine' | 'l2' | 'hamming';\n\n/** Storage precision for a vector index. */\nexport type VectorStorageConfig = 'float32' | 'int8' | 'bit';\n\nexport interface VectorIndexDeclaration {\n collection: string;\n field: string;\n dimensions: number;\n metric?: VectorMetricConfig;\n storage?: VectorStorageConfig;\n matryoshka?: boolean;\n multiVector?: boolean;\n}\n\nexport interface DatabaseConfigBlock {\n /** MongoDB-style secondary indexes. */\n indexes?: DocumentIndexDeclaration[];\n /** sqlite-vec-backed vector indexes. */\n vectorIndexes?: VectorIndexDeclaration[];\n}\n\n/**\n * Identity function that returns the config unchanged — exists purely so the\n * TypeScript compiler can infer `MaravillaConfig` and give you IntelliSense\n * on every field.\n *\n * @example\n * ```typescript\n * import { defineConfig } from '@maravilla-labs/platform/config';\n *\n * export default defineConfig({\n * auth: {\n * resources: [{ name: 'todos', title: 'Todos', actions: ['read', 'write'] }],\n * },\n * });\n * ```\n */\nexport function defineConfig(config: MaravillaConfig): MaravillaConfig {\n return config;\n}\n"],"mappings":";AAmUO,SAAS,aAAa,QAA0C;AACrE,SAAO;AACT;","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -945,6 +945,201 @@ interface UpdateUserOptions {
|
|
|
945
945
|
/** Profile data to merge */
|
|
946
946
|
profile?: Record<string, any>;
|
|
947
947
|
}
|
|
948
|
+
interface AuthGroup {
|
|
949
|
+
id: string;
|
|
950
|
+
name: string;
|
|
951
|
+
description: string | null;
|
|
952
|
+
permissions: string[];
|
|
953
|
+
member_count: number;
|
|
954
|
+
created_at: number;
|
|
955
|
+
updated_at: number;
|
|
956
|
+
}
|
|
957
|
+
interface CreateGroupOptions {
|
|
958
|
+
name: string;
|
|
959
|
+
description?: string;
|
|
960
|
+
permissions?: string[];
|
|
961
|
+
}
|
|
962
|
+
interface UpdateGroupOptions {
|
|
963
|
+
name?: string;
|
|
964
|
+
description?: string;
|
|
965
|
+
permissions?: string[];
|
|
966
|
+
}
|
|
967
|
+
interface GroupPermission {
|
|
968
|
+
resource_name: string;
|
|
969
|
+
actions: string[];
|
|
970
|
+
}
|
|
971
|
+
interface AuthCircle {
|
|
972
|
+
id: string;
|
|
973
|
+
name: string;
|
|
974
|
+
metadata: Record<string, any> | null;
|
|
975
|
+
member_count: number;
|
|
976
|
+
created_at: number;
|
|
977
|
+
updated_at: number;
|
|
978
|
+
}
|
|
979
|
+
interface CreateCircleOptions {
|
|
980
|
+
name: string;
|
|
981
|
+
metadata?: Record<string, any>;
|
|
982
|
+
}
|
|
983
|
+
interface UpdateCircleOptions {
|
|
984
|
+
name?: string;
|
|
985
|
+
metadata?: Record<string, any>;
|
|
986
|
+
}
|
|
987
|
+
interface AddCircleMemberOptions {
|
|
988
|
+
user_id: string;
|
|
989
|
+
relationship: string;
|
|
990
|
+
is_primary_contact?: boolean;
|
|
991
|
+
}
|
|
992
|
+
interface CircleMembership {
|
|
993
|
+
user_id: string;
|
|
994
|
+
email: string;
|
|
995
|
+
relationship: string;
|
|
996
|
+
is_primary_contact: boolean;
|
|
997
|
+
joined_at: number;
|
|
998
|
+
}
|
|
999
|
+
type ResourceServiceType = 'kv' | 'database' | 'realtime' | 'media' | 'vector' | 'storage' | 'queue' | 'push' | 'workflow' | 'transforms';
|
|
1000
|
+
interface Resource {
|
|
1001
|
+
id: string;
|
|
1002
|
+
resource_name: string;
|
|
1003
|
+
title: string;
|
|
1004
|
+
description: string | null;
|
|
1005
|
+
actions: string[];
|
|
1006
|
+
policy: string | null;
|
|
1007
|
+
service_type: ResourceServiceType | null;
|
|
1008
|
+
read_filter: string | null;
|
|
1009
|
+
created_at: number;
|
|
1010
|
+
updated_at: number;
|
|
1011
|
+
}
|
|
1012
|
+
interface CreateResourceOptions {
|
|
1013
|
+
resource_name: string;
|
|
1014
|
+
title: string;
|
|
1015
|
+
description?: string;
|
|
1016
|
+
actions?: string[];
|
|
1017
|
+
policy?: string;
|
|
1018
|
+
service_type?: ResourceServiceType;
|
|
1019
|
+
read_filter?: string;
|
|
1020
|
+
}
|
|
1021
|
+
interface UpdateResourceOptions {
|
|
1022
|
+
title?: string;
|
|
1023
|
+
description?: string;
|
|
1024
|
+
actions?: string[];
|
|
1025
|
+
policy?: string;
|
|
1026
|
+
service_type?: ResourceServiceType;
|
|
1027
|
+
read_filter?: string;
|
|
1028
|
+
}
|
|
1029
|
+
interface RelationType {
|
|
1030
|
+
id: string;
|
|
1031
|
+
relation_name: string;
|
|
1032
|
+
title: string;
|
|
1033
|
+
description: string | null;
|
|
1034
|
+
category: string;
|
|
1035
|
+
icon: string | null;
|
|
1036
|
+
color: string | null;
|
|
1037
|
+
inverse_relation_id: string | null;
|
|
1038
|
+
implies_stewardship: boolean;
|
|
1039
|
+
requires_minor: boolean;
|
|
1040
|
+
bidirectional: boolean;
|
|
1041
|
+
is_system: boolean;
|
|
1042
|
+
created_at: number;
|
|
1043
|
+
updated_at: number;
|
|
1044
|
+
}
|
|
1045
|
+
interface CreateRelationTypeOptions {
|
|
1046
|
+
relation_name: string;
|
|
1047
|
+
title: string;
|
|
1048
|
+
description?: string;
|
|
1049
|
+
category?: string;
|
|
1050
|
+
icon?: string;
|
|
1051
|
+
color?: string;
|
|
1052
|
+
inverse_relation_id?: string;
|
|
1053
|
+
implies_stewardship?: boolean;
|
|
1054
|
+
requires_minor?: boolean;
|
|
1055
|
+
bidirectional?: boolean;
|
|
1056
|
+
is_system?: boolean;
|
|
1057
|
+
}
|
|
1058
|
+
interface UpdateRelationTypeOptions {
|
|
1059
|
+
title?: string;
|
|
1060
|
+
description?: string;
|
|
1061
|
+
category?: string;
|
|
1062
|
+
icon?: string;
|
|
1063
|
+
color?: string;
|
|
1064
|
+
inverse_relation_id?: string;
|
|
1065
|
+
implies_stewardship?: boolean;
|
|
1066
|
+
requires_minor?: boolean;
|
|
1067
|
+
bidirectional?: boolean;
|
|
1068
|
+
}
|
|
1069
|
+
interface AuthConfig {
|
|
1070
|
+
fields: AuthField[];
|
|
1071
|
+
oauth_providers: any[];
|
|
1072
|
+
branding: Record<string, any>;
|
|
1073
|
+
password_policy: Record<string, any>;
|
|
1074
|
+
session_config: Record<string, any>;
|
|
1075
|
+
}
|
|
1076
|
+
type DelegationMode = 'full' | 'scoped';
|
|
1077
|
+
type StewardshipStatus = 'active' | 'suspended' | 'revoked' | 'expired';
|
|
1078
|
+
interface ScopedPermission {
|
|
1079
|
+
resource: string;
|
|
1080
|
+
actions: string[];
|
|
1081
|
+
}
|
|
1082
|
+
interface StewardshipOverride {
|
|
1083
|
+
id: string;
|
|
1084
|
+
steward_id: string;
|
|
1085
|
+
ward_id: string;
|
|
1086
|
+
delegation_mode: DelegationMode;
|
|
1087
|
+
scoped_permissions: ScopedPermission[];
|
|
1088
|
+
valid_from: number | null;
|
|
1089
|
+
valid_until: number | null;
|
|
1090
|
+
status: StewardshipStatus;
|
|
1091
|
+
reason: string | null;
|
|
1092
|
+
source: string;
|
|
1093
|
+
source_circle_id: string | null;
|
|
1094
|
+
source_relation_type_id: string | null;
|
|
1095
|
+
created_at: number;
|
|
1096
|
+
updated_at: number;
|
|
1097
|
+
}
|
|
1098
|
+
interface CreateStewardshipOverrideOptions {
|
|
1099
|
+
steward_id: string;
|
|
1100
|
+
ward_id: string;
|
|
1101
|
+
delegation_mode?: DelegationMode;
|
|
1102
|
+
scoped_permissions?: ScopedPermission[];
|
|
1103
|
+
valid_from?: number;
|
|
1104
|
+
valid_until?: number;
|
|
1105
|
+
reason?: string;
|
|
1106
|
+
}
|
|
1107
|
+
interface StewardshipResolution {
|
|
1108
|
+
stewards: StewardshipOverride[];
|
|
1109
|
+
wards: StewardshipOverride[];
|
|
1110
|
+
}
|
|
1111
|
+
interface ActAsContext {
|
|
1112
|
+
steward_id: string;
|
|
1113
|
+
ward_id: string;
|
|
1114
|
+
delegation_mode: DelegationMode;
|
|
1115
|
+
scoped_permissions: ScopedPermission[];
|
|
1116
|
+
session_token: string;
|
|
1117
|
+
expires_at: number;
|
|
1118
|
+
}
|
|
1119
|
+
interface StewardshipAuditEntry {
|
|
1120
|
+
id: string;
|
|
1121
|
+
performed_by: string;
|
|
1122
|
+
on_behalf_of: string;
|
|
1123
|
+
action: string;
|
|
1124
|
+
resource: string | null;
|
|
1125
|
+
details: Record<string, any> | null;
|
|
1126
|
+
created_at: number;
|
|
1127
|
+
}
|
|
1128
|
+
/**
|
|
1129
|
+
* Sub-namespace exposed at `platform.auth.stewardship` mirroring the
|
|
1130
|
+
* runtime's `globalThis.platform.auth.stewardship.*` surface.
|
|
1131
|
+
*/
|
|
1132
|
+
interface AuthStewardshipApi {
|
|
1133
|
+
resolve(userId: string): Promise<StewardshipResolution>;
|
|
1134
|
+
createOverride(opts: CreateStewardshipOverrideOptions): Promise<StewardshipOverride>;
|
|
1135
|
+
revoke(id: string): Promise<void>;
|
|
1136
|
+
checkPermission(stewardId: string, wardId: string, resource: string, action: string): Promise<boolean>;
|
|
1137
|
+
createActAs(stewardId: string, wardId: string): Promise<ActAsContext>;
|
|
1138
|
+
listAudit(userId: string, options?: {
|
|
1139
|
+
limit?: number;
|
|
1140
|
+
offset?: number;
|
|
1141
|
+
}): Promise<StewardshipAuditEntry[]>;
|
|
1142
|
+
}
|
|
948
1143
|
/**
|
|
949
1144
|
* Auth service for end-user authentication and user management.
|
|
950
1145
|
*
|
|
@@ -1106,6 +1301,39 @@ interface AuthService {
|
|
|
1106
1301
|
withAuth<T extends (request: Request & {
|
|
1107
1302
|
user: AuthUser;
|
|
1108
1303
|
}) => Promise<Response>>(handler: T): (request: Request) => Promise<Response>;
|
|
1304
|
+
createGroup(options: CreateGroupOptions): Promise<AuthGroup>;
|
|
1305
|
+
listGroups(): Promise<AuthGroup[]>;
|
|
1306
|
+
getGroup(groupId: string): Promise<AuthGroup | null>;
|
|
1307
|
+
updateGroup(groupId: string, options: UpdateGroupOptions): Promise<AuthGroup>;
|
|
1308
|
+
deleteGroup(groupId: string): Promise<void>;
|
|
1309
|
+
addUserToGroup(userId: string, groupId: string): Promise<void>;
|
|
1310
|
+
removeUserFromGroup(userId: string, groupId: string): Promise<void>;
|
|
1311
|
+
getUserGroups(userId: string): Promise<AuthGroup[]>;
|
|
1312
|
+
getGroupMembers(groupId: string): Promise<AuthUser[]>;
|
|
1313
|
+
getGroupPermissions(groupId: string): Promise<GroupPermission[]>;
|
|
1314
|
+
setGroupPermissions(groupId: string, permissions: GroupPermission[]): Promise<void>;
|
|
1315
|
+
createCircle(options: CreateCircleOptions): Promise<AuthCircle>;
|
|
1316
|
+
listCircles(): Promise<AuthCircle[]>;
|
|
1317
|
+
getCircle(circleId: string): Promise<AuthCircle | null>;
|
|
1318
|
+
updateCircle(circleId: string, options: UpdateCircleOptions): Promise<AuthCircle>;
|
|
1319
|
+
deleteCircle(circleId: string): Promise<void>;
|
|
1320
|
+
addCircleMember(circleId: string, options: AddCircleMemberOptions): Promise<void>;
|
|
1321
|
+
removeCircleMember(circleId: string, userId: string): Promise<void>;
|
|
1322
|
+
getCircleMembers(circleId: string): Promise<CircleMembership[]>;
|
|
1323
|
+
getUserCircles(userId: string): Promise<AuthCircle[]>;
|
|
1324
|
+
createResource(options: CreateResourceOptions): Promise<Resource>;
|
|
1325
|
+
listResources(): Promise<Resource[]>;
|
|
1326
|
+
updateResource(resourceId: string, options: UpdateResourceOptions): Promise<Resource>;
|
|
1327
|
+
deleteResource(resourceId: string): Promise<void>;
|
|
1328
|
+
createRelationType(options: CreateRelationTypeOptions): Promise<RelationType>;
|
|
1329
|
+
listRelationTypes(): Promise<RelationType[]>;
|
|
1330
|
+
updateRelationType(id: string, options: UpdateRelationTypeOptions): Promise<RelationType>;
|
|
1331
|
+
deleteRelationType(id: string): Promise<void>;
|
|
1332
|
+
getProfile(userId: string): Promise<Record<string, any>>;
|
|
1333
|
+
setProfile(userId: string, data: Record<string, any>): Promise<void>;
|
|
1334
|
+
getAuthConfig(): Promise<AuthConfig>;
|
|
1335
|
+
setAuthConfig(config: AuthConfig): Promise<void>;
|
|
1336
|
+
readonly stewardship: AuthStewardshipApi;
|
|
1109
1337
|
/**
|
|
1110
1338
|
* Explicitly bind the caller for the remainder of this request.
|
|
1111
1339
|
* Pass a JWT to validate + bind, or `null` / `""` to clear.
|
|
@@ -1652,6 +1880,64 @@ declare class MediaRoom {
|
|
|
1652
1880
|
private wireEvents;
|
|
1653
1881
|
}
|
|
1654
1882
|
|
|
1883
|
+
/**
|
|
1884
|
+
* Per-request scope for the SDK's remote client. Mirrors the runtime's
|
|
1885
|
+
* `REQUEST_CTX` (a `tokio::task_local!` in Rust) so that
|
|
1886
|
+
* `platform.auth.setCurrentUser(token)`, `getCurrentUser()`, and `can()`
|
|
1887
|
+
* — plus future per-request state like the Layer-2 policy toggle —
|
|
1888
|
+
* have a place to live when the SDK is running outside the runtime
|
|
1889
|
+
* (Vite SSR, Node.js HTTP servers, edge workers that expose Node APIs).
|
|
1890
|
+
*
|
|
1891
|
+
* Implementation: Node's `AsyncLocalStorage`. Tenant code wraps each
|
|
1892
|
+
* inbound request with `runWithRequest(async () => { ... })` so the
|
|
1893
|
+
* store stays scoped to the request's async chain. `setCurrentUser`
|
|
1894
|
+
* / `can` read and write that store; if a tenant forgets to wrap, the
|
|
1895
|
+
* methods either no-op (set) or throw a clear error (get/can).
|
|
1896
|
+
*/
|
|
1897
|
+
|
|
1898
|
+
interface RequestStore {
|
|
1899
|
+
/** Bound access-token JWT (set by `auth.setCurrentUser`). */
|
|
1900
|
+
token?: string;
|
|
1901
|
+
/** Bound user (cached so `getCurrentUser` doesn't re-validate). */
|
|
1902
|
+
user?: AuthUser;
|
|
1903
|
+
/** Whether Layer-2 policy enforcement is enabled for this request. */
|
|
1904
|
+
policyEnabled: boolean;
|
|
1905
|
+
}
|
|
1906
|
+
/**
|
|
1907
|
+
* Wrap a function in a fresh request scope. **Rarely needed** — the
|
|
1908
|
+
* Maravilla Vite plugin (`@maravilla-labs/vite-plugin`) auto-opens a
|
|
1909
|
+
* scope around every inbound dev HTTP request, so tenant code
|
|
1910
|
+
* (SvelteKit `hooks.server.ts`, RR/Remix loaders, etc.) reaches
|
|
1911
|
+
* `setCurrentUser/getCurrentUser/can` with a scope already active.
|
|
1912
|
+
*
|
|
1913
|
+
* Reach for `runWithRequest` only when the SDK runs **outside** an
|
|
1914
|
+
* HTTP request: standalone Node scripts, test fixtures, custom
|
|
1915
|
+
* servers that don't go through Vite. Inside an active scope,
|
|
1916
|
+
* `platform.auth.setCurrentUser/getCurrentUser/can` operate on a
|
|
1917
|
+
* per-request store keyed by Node's `AsyncLocalStorage`.
|
|
1918
|
+
*
|
|
1919
|
+
* @example
|
|
1920
|
+
* ```ts
|
|
1921
|
+
* // Test fixture that needs to bind a user before exercising the SDK
|
|
1922
|
+
* await runWithRequest(async () => {
|
|
1923
|
+
* await getPlatform().auth.setCurrentUser(testToken);
|
|
1924
|
+
* const result = await getPlatform().env.DB.find('users', {});
|
|
1925
|
+
* expect(result).toEqual(...);
|
|
1926
|
+
* });
|
|
1927
|
+
* ```
|
|
1928
|
+
*/
|
|
1929
|
+
declare function runWithRequest<T>(fn: () => Promise<T> | T): Promise<T>;
|
|
1930
|
+
/**
|
|
1931
|
+
* Read the current request's store, if any. Returns undefined when
|
|
1932
|
+
* called outside a `runWithRequest` scope. Used by `RemoteAuthService`
|
|
1933
|
+
* and (future) other Remote* services to source per-request state.
|
|
1934
|
+
*
|
|
1935
|
+
* Note: the `als` may not yet be initialised when this is called; in
|
|
1936
|
+
* that case the function returns undefined synchronously. Subsequent
|
|
1937
|
+
* `runWithRequest` calls will populate it.
|
|
1938
|
+
*/
|
|
1939
|
+
declare function getCurrentRequestStore(): RequestStore | undefined;
|
|
1940
|
+
|
|
1655
1941
|
/**
|
|
1656
1942
|
* @fileoverview Maravilla Platform SDK
|
|
1657
1943
|
*
|
|
@@ -1772,4 +2058,4 @@ declare function getPlatform(options?: {
|
|
|
1772
2058
|
*/
|
|
1773
2059
|
declare function clearPlatformCache(): void;
|
|
1774
2060
|
|
|
1775
|
-
export { type AuthCaller, type AuthField, type AuthService, type AuthSession, type AuthUser, type Database, type DbFindOptions, type IndexDescriptor, type IndexDirection, type IndexKind, type IndexSpec, type KvListResult, type KvNamespace, type ListScheduledFilter, type LoginOptions, MediaLocalParticipant, type MediaParticipant, type MediaParticipantInfo, MediaRoom, MediaRoomEvent, type MediaRoomInfo, type MediaRoomInfoSettings, type MediaRoomOptions, type MediaService, type MediaTokenResult, type MediaTrackPublication, type NotificationPayload, type Platform, type PlatformEnv, type PolicyService, type PresenceMember, type PresenceService, type PublicPushConfig, type PushService, type PushTarget, type QueueStats, RealtimeClient, type RealtimeClientOptions, type RealtimeEvent, type RealtimeService, type RegisterOptions, RemoteMediaService, type ScheduleOptions, type ScheduledJob, type SendReport, type Storage, type StoragePutStreamSource, type StoredPushSubscription, type SubscriptionCounts, type TrackKind, type TrackSource, type UpdateUserOptions, type UserListFilter, type UserListResponse, type VectorAggregation, type VectorIndexDescriptor, type VectorIndexSpec, type VectorMetric, type VectorQuery, type VectorQueryMode, type VectorQueryWithFilter, type VectorSearchHit, type VectorStorage, type VideoResolution, type WorkflowHandle, type WorkflowRun, type WorkflowRunStatus, type WorkflowStepKind, type WorkflowStepRecord, type Workflows, attachTrack, clearPlatformCache, detachTrack, getPlatform };
|
|
2061
|
+
export { type ActAsContext, type AddCircleMemberOptions, type AuthCaller, type AuthCircle, type AuthConfig, type AuthField, type AuthGroup, type AuthService, type AuthSession, type AuthStewardshipApi, type AuthUser, type CircleMembership, type CreateCircleOptions, type CreateGroupOptions, type CreateRelationTypeOptions, type CreateResourceOptions, type CreateStewardshipOverrideOptions, type Database, type DbFindOptions, type DelegationMode, type GroupPermission, type IndexDescriptor, type IndexDirection, type IndexKind, type IndexSpec, type KvListResult, type KvNamespace, type ListScheduledFilter, type LoginOptions, MediaLocalParticipant, type MediaParticipant, type MediaParticipantInfo, MediaRoom, MediaRoomEvent, type MediaRoomInfo, type MediaRoomInfoSettings, type MediaRoomOptions, type MediaService, type MediaTokenResult, type MediaTrackPublication, type NotificationPayload, type Platform, type PlatformEnv, type PolicyService, type PresenceMember, type PresenceService, type PublicPushConfig, type PushService, type PushTarget, type QueueStats, RealtimeClient, type RealtimeClientOptions, type RealtimeEvent, type RealtimeService, type RegisterOptions, type RelationType, RemoteMediaService, type RequestStore, type Resource, type ResourceServiceType, type ScheduleOptions, type ScheduledJob, type ScopedPermission, type SendReport, type StewardshipAuditEntry, type StewardshipOverride, type StewardshipResolution, type StewardshipStatus, type Storage, type StoragePutStreamSource, type StoredPushSubscription, type SubscriptionCounts, type TrackKind, type TrackSource, type UpdateCircleOptions, type UpdateGroupOptions, type UpdateRelationTypeOptions, type UpdateResourceOptions, type UpdateUserOptions, type UserListFilter, type UserListResponse, type VectorAggregation, type VectorIndexDescriptor, type VectorIndexSpec, type VectorMetric, type VectorQuery, type VectorQueryMode, type VectorQueryWithFilter, type VectorSearchHit, type VectorStorage, type VideoResolution, type WorkflowHandle, type WorkflowRun, type WorkflowRunStatus, type WorkflowStepKind, type WorkflowStepRecord, type Workflows, attachTrack, clearPlatformCache, detachTrack, getCurrentRequestStore, getPlatform, runWithRequest };
|