@raisindb/functions-types 0.2.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/raisin.d.ts +141 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raisindb/functions-types",
3
- "version": "0.2.5",
3
+ "version": "0.3.0",
4
4
  "description": "TypeScript type definitions for the RaisinDB server-side function runtime (QuickJS)",
5
5
  "license": "MIT",
6
6
  "types": "raisin.d.ts",
package/raisin.d.ts CHANGED
@@ -393,6 +393,147 @@ declare namespace raisin {
393
393
  function get(jobIdOrKey: string): Promise<any>;
394
394
  }
395
395
 
396
+ /**
397
+ * Metadata about one secret. Never carries the secret itself — the type has
398
+ * no field that could hold ciphertext or plaintext.
399
+ */
400
+ interface SecretMetadata {
401
+ name: string;
402
+ /** Human-facing ordinal, from 1. Use it as `secrets.get(name, version)`. */
403
+ version: number;
404
+ /** Which master key sealed it. */
405
+ key_id: number;
406
+ /** RFC 3339. */
407
+ created_at: string;
408
+ created_by: string;
409
+ /** Set only by `rotate`. */
410
+ rotated_at?: string | null;
411
+ /** The node this secret backs, when it is a vaulted schema field. */
412
+ owner_node?: string | null;
413
+ owner_field?: string | null;
414
+ /** True when the newest version is a tombstone. */
415
+ deleted: boolean;
416
+ ciphertext_len: number;
417
+ }
418
+
419
+ /**
420
+ * Encrypted secret store, scoped to the current `{tenant, repo, branch}`.
421
+ *
422
+ * **Access is denied by default.** A function reaches these only if its
423
+ * `.node.yaml` declares a matching grant:
424
+ *
425
+ * ```yaml
426
+ * secret_policy:
427
+ * enabled: true
428
+ * allowed_names:
429
+ * - "stripe/*"
430
+ * - "sendgrid_api_key"
431
+ * ```
432
+ *
433
+ * Without one, every call below throws a `policy_denied` error naming the
434
+ * secret. That default is deliberate: adapters run privileged and hold
435
+ * `raisin.http`, so an ungated secrets binding would be a one-line
436
+ * exfiltration path for every credential in the repo.
437
+ *
438
+ * Every method THROWS on failure (denial, missing secret, deleted secret,
439
+ * unconfigured store) — none of them degrade to `null`, which would be
440
+ * indistinguishable from an empty credential.
441
+ *
442
+ * ## The main flow: a secret stored in a node property
443
+ *
444
+ * The common case is not a standalone secret — it is a field on a regular
445
+ * node declared `encrypted: true` in its NodeType. Three steps:
446
+ *
447
+ * 1. The property does not hold the credential. It holds a REFERENCE:
448
+ * `"secret://node/01H8XY.../api_key@1"`.
449
+ * 2. A node read returns that string verbatim. **Reads never resolve** —
450
+ * there is no query flag and no endpoint that returns a value.
451
+ * 3. The function passes the string straight to `get` (or `resolve`):
452
+ *
453
+ * ```javascript
454
+ * const node = await raisin.nodes.get('data', '/connections/stripe');
455
+ * const key = raisin.secrets.get(node.properties.api_key);
456
+ * ```
457
+ *
458
+ * Pass the reference through **as-is**. Do not strip `secret://` or the
459
+ * `@version` suffix yourself: a name may itself contain `@` (an operator
460
+ * name like `ops@example.com`), so only a trailing all-digit run after the
461
+ * LAST `@` is a version. `get` applies that rule using the same parser the
462
+ * storage layer uses.
463
+ */
464
+ /**
465
+ * Declared as an interface rather than a `namespace`, because `delete` is a
466
+ * reserved word that TypeScript rejects as an ambient `function` name but
467
+ * accepts as an interface method. (The `http`, `nodes` and `admin.nodes`
468
+ * namespaces above still use `function delete(...)`, which does not parse —
469
+ * a pre-existing break, unnoticed because this package has no drift test.)
470
+ */
471
+ interface SecretsApi {
472
+ /**
473
+ * Read a secret's plaintext.
474
+ *
475
+ * `nameOrRef` is EITHER a bare name (`"stripe_key"`) or a full reference
476
+ * (`"secret://node/01H8XY.../api_key@1"`) — see the three-step flow above
477
+ * for why the reference form is what you will usually be holding.
478
+ *
479
+ * A version pinned in the reference is HONOURED: `secret://k@1` returns
480
+ * version 1, not the latest. That is what makes reading an older node
481
+ * revision give the value that revision actually held.
482
+ *
483
+ * Passing the `version` argument **and** a pinned reference throws. Two
484
+ * stated versions cannot both be satisfied, and silently preferring either
485
+ * could return a value the node revision never held — which is the exact
486
+ * guarantee a pinned reference exists to provide. Pass one or the other;
487
+ * `get('k', 2)` and `get('secret://k', 2)` are both fine.
488
+ *
489
+ * The policy allow-list is matched against the parsed NAME, so both
490
+ * spellings of one secret always get the same allow/deny answer.
491
+ *
492
+ * Throws if the policy denies the name, or the secret is missing or
493
+ * deleted.
494
+ */
495
+ get(nameOrRef: string, version?: number): Promise<string>;
496
+ /**
497
+ * Resolve a value that MAY be a `secret://` reference.
498
+ *
499
+ * Returns the plaintext when it is one, or the value unchanged when it is
500
+ * not — so a config field that is a literal password on one deployment and
501
+ * a vaulted reference on another is read the same way:
502
+ *
503
+ * ```javascript
504
+ * const password = raisin.secrets.resolve(conn.password);
505
+ * ```
506
+ *
507
+ * A reference that fails to resolve THROWS; it never falls back to
508
+ * returning the reference text, which would send `secret://...` to a
509
+ * provider as a credential. A plain literal is passed through without any
510
+ * policy check, since no secret was touched.
511
+ */
512
+ resolve(value: string): Promise<string>;
513
+ /**
514
+ * Append a new version. Never overwrites — prior versions stay readable.
515
+ *
516
+ * Accepts a bare name or an UNPINNED reference; a pinned one
517
+ * (`secret://k@1`) is refused, because a write appends a new version
518
+ * rather than replacing that one.
519
+ */
520
+ put(name: string, value: string): Promise<{ name: string; version: number }>;
521
+ /**
522
+ * Metadata for the newest version of every secret this function may read.
523
+ * Never returns values, and is filtered to the policy's allowed names.
524
+ */
525
+ list(): Promise<SecretMetadata[]>;
526
+ /**
527
+ * Append a new version stamped as a rotation. Pinned `secret://name@N`
528
+ * references keep resolving to the old version.
529
+ */
530
+ rotate(name: string, value: string): Promise<{ name: string; version: number }>;
531
+ /** Append a tombstone. Prior versions remain readable by pinned reference. */
532
+ delete(name: string): Promise<{ name: string; version: number }>;
533
+ }
534
+
535
+ const secrets: SecretsApi;
536
+
396
537
  namespace sql {
397
538
  function query(sql: string, params: any[]): Promise<any>;
398
539
  function execute(sql: string, params: any[]): Promise<number>;