@rebasepro/types 0.10.1-canary.6f89f77 → 0.10.1-canary.7e63575

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/index.es.js CHANGED
@@ -416,6 +416,19 @@ function isBranchAdmin(admin) {
416
416
  return !!admin && typeof admin.createBranch === "function";
417
417
  }
418
418
  //#endregion
419
+ //#region src/types/channel_bus.ts
420
+ /**
421
+ * Whether `setting` is an already-constructed transport rather than a request
422
+ * for a built-in one.
423
+ *
424
+ * Structural rather than nominal so that an instance from a *different copy* of
425
+ * `@rebasepro/types` — an entirely normal outcome of a separately versioned
426
+ * transport package — is still recognised.
427
+ */
428
+ function isChannelBusInstance(setting) {
429
+ return typeof setting?.publish === "function";
430
+ }
431
+ //#endregion
419
432
  //#region src/types/data_source.ts
420
433
  /**
421
434
  * The default data-source key, used when a collection does not name a
@@ -541,6 +554,235 @@ function isLazyComponentRef(ref) {
541
554
  return typeof ref === "object" && ref !== null && "__rebaseLazy" in ref && ref.__rebaseLazy === true;
542
555
  }
543
556
  //#endregion
557
+ //#region src/types/project_manifest.ts
558
+ /**
559
+ * Version of the bundle *format* itself.
560
+ *
561
+ * Bumped only when the on-disk layout changes in a way an older runtime could
562
+ * not read. A runtime accepts any bundle whose `bundleFormat` is less than or
563
+ * equal to its own — old bundles keep booting on new runtimes, which is the
564
+ * whole point of separating the artifact from the engine.
565
+ */
566
+ var BUNDLE_FORMAT_VERSION = 1;
567
+ /**
568
+ * The runtime contract major.
569
+ *
570
+ * Distinct from the `@rebasepro/server` package version: the package may release
571
+ * any number of minors and patches while this stays put. It changes only when
572
+ * the bundle/runtime contract breaks compatibility, and a project's
573
+ * `manifest.runtime` range is matched against *this*.
574
+ */
575
+ var RUNTIME_CONTRACT_VERSION = 1;
576
+ /** Header carrying the schema version an SDK was generated from. */
577
+ var SCHEMA_VERSION_HEADER = "x-rebase-schema";
578
+ //#endregion
579
+ //#region src/types/collection_contract.ts
580
+ function isSerializedCollectionRef(value) {
581
+ return typeof value === "object" && value !== null && typeof value.__collectionRef === "string";
582
+ }
583
+ /** Depth limit for the walk — deep enough for real configs, finite for cyclic ones. */
584
+ var MAX_DEPTH = 64;
585
+ /**
586
+ * Resolve whatever a `target` thunk returns down to a collection.
587
+ *
588
+ * A target may be the collection, a module namespace (when the authoring file
589
+ * used `import * as`), or a default-export wrapper. All three appear in real
590
+ * projects, and the SDK generator already unwraps them the same way.
591
+ */
592
+ function unwrapTarget(value) {
593
+ if (!value || typeof value !== "object") return void 0;
594
+ const candidate = value;
595
+ if (candidate.default || candidate.__esModule) {
596
+ const inner = candidate.default;
597
+ if (inner && typeof inner === "object") return inner;
598
+ }
599
+ if (candidate.properties) return value;
600
+ }
601
+ /** The identity a serialized reference uses. Slug first — it is the routing key. */
602
+ function refFor(collection) {
603
+ if (!collection) return void 0;
604
+ const withPath = collection;
605
+ return collection.slug || withPath.path || collection.name;
606
+ }
607
+ function toSerializable(value, seen, depth, state, key) {
608
+ if (depth > MAX_DEPTH) {
609
+ state.truncations++;
610
+ return;
611
+ }
612
+ if (typeof value === "function") {
613
+ if (key === "target") try {
614
+ const ref = refFor(unwrapTarget(value()));
615
+ return ref ? { __collectionRef: ref } : void 0;
616
+ } catch {
617
+ return;
618
+ }
619
+ return;
620
+ }
621
+ if (value === null || typeof value !== "object") return value;
622
+ if (value instanceof Date) return value.toISOString();
623
+ if (value instanceof RegExp) return value.source;
624
+ if (seen.has(value)) {
625
+ state.truncations++;
626
+ return;
627
+ }
628
+ const cached = state.memo.get(value);
629
+ if (cached !== void 0) return cached;
630
+ seen.add(value);
631
+ const truncationsBefore = state.truncations;
632
+ const memoize = (result) => {
633
+ if (result !== void 0 && state.truncations === truncationsBefore) state.memo.set(value, result);
634
+ return result;
635
+ };
636
+ try {
637
+ if (Array.isArray(value)) {
638
+ const items = value.map((item) => toSerializable(item, seen, depth + 1, state)).filter((item) => item !== void 0);
639
+ return memoize(value.length > 0 && items.length === 0 ? void 0 : items);
640
+ }
641
+ if ("$$typeof" in value) return void 0;
642
+ const entries = Object.entries(value);
643
+ const out = {};
644
+ for (const [k, v] of entries) {
645
+ const converted = toSerializable(v, seen, depth + 1, state, k);
646
+ if (converted !== void 0) out[k] = converted;
647
+ }
648
+ if (entries.length > 0 && Object.keys(out).length === 0) return void 0;
649
+ return memoize(out);
650
+ } finally {
651
+ seen.delete(value);
652
+ }
653
+ }
654
+ /**
655
+ * Serialize collections for transport over the contract endpoint.
656
+ *
657
+ * Sorted by slug so the output — and therefore the schema hash computed from it
658
+ * — does not depend on filesystem ordering.
659
+ */
660
+ function serializeCollections(collections) {
661
+ return [...collections].sort((a, b) => String(a.slug ?? "").localeCompare(String(b.slug ?? ""))).map((collection) => toSerializable(collection, /* @__PURE__ */ new WeakSet(), 0, {
662
+ memo: /* @__PURE__ */ new WeakMap(),
663
+ truncations: 0
664
+ })).filter((c) => c !== void 0);
665
+ }
666
+ /**
667
+ * Rebuild collections received from a contract endpoint.
668
+ *
669
+ * Relation refs become real thunks resolving through the returned set, so
670
+ * downstream consumers — the SDK generator above all — see exactly the shape
671
+ * they would have seen had the collections been imported from source.
672
+ *
673
+ * A ref naming a collection that is not in the payload resolves to `undefined`
674
+ * rather than throwing: the generator already tolerates an unresolvable target
675
+ * by falling back to a permissive key type, and a partial contract should still
676
+ * produce a usable SDK.
677
+ */
678
+ function deserializeCollections(payload) {
679
+ const collections = payload.filter((c) => typeof c === "object" && c !== null).map((c) => ({ ...c }));
680
+ const bySlug = /* @__PURE__ */ new Map();
681
+ for (const collection of collections) {
682
+ const ref = refFor(collection);
683
+ if (ref) bySlug.set(ref, collection);
684
+ }
685
+ const rehydrate = (value, depth) => {
686
+ if (depth > MAX_DEPTH || !value || typeof value !== "object") return;
687
+ if (Array.isArray(value)) {
688
+ for (const item of value) rehydrate(item, depth + 1);
689
+ return;
690
+ }
691
+ const record = value;
692
+ for (const [key, child] of Object.entries(record)) {
693
+ if (key === "target" && isSerializedCollectionRef(child)) {
694
+ const slug = child.__collectionRef;
695
+ record.target = () => bySlug.get(slug);
696
+ continue;
697
+ }
698
+ rehydrate(child, depth + 1);
699
+ }
700
+ };
701
+ for (const collection of collections) rehydrate(collection, 0);
702
+ return collections;
703
+ }
704
+ //#endregion
705
+ //#region src/types/schema_version.ts
706
+ /**
707
+ * The schema version stamp.
708
+ *
709
+ * One function, used in three places that must agree or the whole drift-detection
710
+ * story is noise: `rebase build` writes it into a bundle manifest, the runtime
711
+ * serves it from the contract endpoint, and a generated SDK records the value it
712
+ * was built from. If any two of those computed it differently, every client would
713
+ * look permanently out of date.
714
+ *
715
+ * It covers **collections only** — the client's contract is the shape of the
716
+ * data, so editing a hook or a server function must not invalidate every SDK in
717
+ * every repository. That is a deliberate narrowing, not an oversight.
718
+ */
719
+ /** Stable stringify: object keys sorted at every level, so key order cannot alter the hash. */
720
+ function canonicalize(value) {
721
+ if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "null";
722
+ if (Array.isArray(value)) return `[${value.map(canonicalize).join(",")}]`;
723
+ return `{${Object.entries(value).filter(([, v]) => v !== void 0).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([k, v]) => `${JSON.stringify(k)}:${canonicalize(v)}`).join(",")}}`;
724
+ }
725
+ /**
726
+ * Reduce a collection to the parts a generated client is actually built from.
727
+ *
728
+ * The version answers one question — "is this SDK stale?" — so it must change
729
+ * exactly when the generated types could change, and never otherwise. Hashing a
730
+ * whole collection fails both halves of that:
731
+ *
732
+ * - Security rules, callbacks, icons, groups and UI settings do not appear in a
733
+ * generated client, so including them reports perfectly current SDKs as stale.
734
+ * - Worse, they are not stable *inputs*. The runtime applies default security
735
+ * rules when it loads collections, so the same source hashed before and after
736
+ * loading produced two different answers — a build-time stamp that could never
737
+ * match the server that served it.
738
+ *
739
+ * Codegen reads the slug (for the `Database` key and type names), the properties,
740
+ * and the relations. That is the projection.
741
+ */
742
+ function projectForCodegen(collection) {
743
+ const source = collection;
744
+ return {
745
+ slug: collection.slug ?? source.path,
746
+ properties: collection.properties,
747
+ relations: source.relations,
748
+ engine: source.engine,
749
+ dataSource: source.dataSource,
750
+ subcollections: source.subcollections?.map(projectForCodegen)
751
+ };
752
+ }
753
+ /**
754
+ * Compute the canonical string a schema version hashes.
755
+ *
756
+ * Exposed separately so the hashing itself can differ by environment: Node has
757
+ * `crypto`, and callers without it can still compare canonical forms directly.
758
+ */
759
+ function canonicalSchemaPayload(collections) {
760
+ return canonicalize(serializeCollections(collections).map((collection) => projectForCodegen(collection)));
761
+ }
762
+ /**
763
+ * A short, non-cryptographic digest of the canonical payload.
764
+ *
765
+ * FNV-1a style, 64 bits, as two 32-bit halves. This is an identity, not a
766
+ * security boundary: nothing trusts a schema version to prove anything, it only
767
+ * answers "is this the same schema as before". A hand-rolled hash keeps this
768
+ * module free of `node:crypto`, so the identical function runs in the browser,
769
+ * in the CLI, and in the runtime — which is the property that actually matters.
770
+ */
771
+ function computeSchemaVersion(collections) {
772
+ const payload = canonicalSchemaPayload(collections);
773
+ let h1 = 2166136261;
774
+ let h2 = 16777619;
775
+ for (let i = 0; i < payload.length; i++) {
776
+ const code = payload.charCodeAt(i);
777
+ h1 ^= code;
778
+ h1 = h1 + ((h1 << 1) + (h1 << 4) + (h1 << 7) + (h1 << 8) + (h1 << 24)) >>> 0;
779
+ h2 ^= code + i;
780
+ h2 = h2 + ((h2 << 1) + (h2 << 5) + (h2 << 9) + (h2 << 15) + (h2 << 24)) >>> 0;
781
+ }
782
+ const hex = (n) => n.toString(16).padStart(8, "0");
783
+ return `v1:${hex(h1)}${hex(h2)}`;
784
+ }
785
+ //#endregion
544
786
  //#region src/controllers/data_driver.ts
545
787
  /** Rows returned for a plain / text-search list read when the client sends no `limit`. */
546
788
  var DEFAULT_LIST_LIMIT = 50;
@@ -595,6 +837,6 @@ function isPublicStoragePath(path) {
595
837
  return p.startsWith("public/") || p.startsWith(`default/public/`);
596
838
  }
597
839
  //#endregion
598
- export { ALL_WHERE_FILTER_OPS, ANONYMOUS_USER_ID, CANONICAL_TO_REST, DEFAULT_CAPABILITIES, DEFAULT_DATA_SOURCE_KEY, DEFAULT_LIST_LIMIT, DEFAULT_STORAGE_SOURCE_KEY, DEFAULT_VECTOR_LIST_LIMIT, EntityReference, EntityRelation, FIREBASE_CAPABILITIES, GeoPoint, MAX_LIST_LIMIT, MONGODB_CAPABILITIES, NULL_OPS, POSTGRES_CAPABILITIES, PUBLIC_STORAGE_PREFIX, REST_TO_CANONICAL, RebaseApiError, RebaseClientError, Vector, getCollectionDataPath, getDataSourceCapabilities, getDeclaredSubcollections, isBranchAdmin, isDocumentAdmin, isFirebaseCollectionConfig, isLazyComponentRef, isMongoDBCollectionConfig, isPostgresCollectionConfig, isPublicStoragePath, isSQLAdmin, isSchemaAdmin, policy, registerDataSourceCapabilities, resolveClientListLimit, toCanonicalOp };
840
+ export { ALL_WHERE_FILTER_OPS, ANONYMOUS_USER_ID, BUNDLE_FORMAT_VERSION, CANONICAL_TO_REST, DEFAULT_CAPABILITIES, DEFAULT_DATA_SOURCE_KEY, DEFAULT_LIST_LIMIT, DEFAULT_STORAGE_SOURCE_KEY, DEFAULT_VECTOR_LIST_LIMIT, EntityReference, EntityRelation, FIREBASE_CAPABILITIES, GeoPoint, MAX_LIST_LIMIT, MONGODB_CAPABILITIES, NULL_OPS, POSTGRES_CAPABILITIES, PUBLIC_STORAGE_PREFIX, REST_TO_CANONICAL, RUNTIME_CONTRACT_VERSION, RebaseApiError, RebaseClientError, SCHEMA_VERSION_HEADER, Vector, canonicalSchemaPayload, computeSchemaVersion, deserializeCollections, getCollectionDataPath, getDataSourceCapabilities, getDeclaredSubcollections, isBranchAdmin, isChannelBusInstance, isDocumentAdmin, isFirebaseCollectionConfig, isLazyComponentRef, isMongoDBCollectionConfig, isPostgresCollectionConfig, isPublicStoragePath, isSQLAdmin, isSchemaAdmin, isSerializedCollectionRef, policy, registerDataSourceCapabilities, resolveClientListLimit, serializeCollections, toCanonicalOp };
599
841
 
600
842
  //# sourceMappingURL=index.es.js.map