@absolutejs/absolute 0.20.0-beta.14 → 0.20.0-beta.15

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/README.md CHANGED
@@ -189,6 +189,13 @@ owns persisted data declares its JSON-safe evolution in `package.json`:
189
189
  Absolute derives stable component IDs from package names, keeps independent
190
190
  version ledgers, validates migration gaps during build/doctor, and applies the
191
191
  same transaction atomically in IndexedDB or Capacitor SQLite before Sync starts.
192
+ The same `localSchema` object can declare `localData` rules for sensitivity,
193
+ encryption, memory-only fallback, whole-cache retention, eviction priority, and
194
+ per-principal quota. Absolute mobile stores record payloads as AES-256-GCM
195
+ ciphertext using a random key held by Keychain/Keystore; native background Sync
196
+ uses the identical authenticated format. Browsers without an audited key
197
+ provider either keep a declared fallback in memory only or fail closed. Pending
198
+ mutations are never evicted to satisfy quota.
192
199
 
193
200
  App updates are consent-driven: `onUpdateAvailable()` latches a waiting worker
194
201
  for late UI subscribers, `checkForUpdate()` performs a passive check, and
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  var __require = import.meta.require;
3
3
 
4
- // .angular-partial-tmp-4ueezp/src/core/streamingSlotRegistrar.ts
4
+ // .angular-partial-tmp-L9oYfg/src/core/streamingSlotRegistrar.ts
5
5
  var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
6
6
  var STREAMING_SLOT_WARNING_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotWarningController");
7
7
  var STREAMING_SLOT_COLLECTION_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotCollectionController");
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  var __require = import.meta.require;
3
3
 
4
- // .angular-partial-tmp-4ueezp/src/core/streamingSlotRegistrar.ts
4
+ // .angular-partial-tmp-L9oYfg/src/core/streamingSlotRegistrar.ts
5
5
  var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
6
6
  var STREAMING_SLOT_WARNING_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotWarningController");
7
7
  var STREAMING_SLOT_COLLECTION_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotCollectionController");
@@ -48,7 +48,7 @@ var warnMissingStreamingSlotCollector = (primitiveName) => {
48
48
  getWarningController()?.maybeWarn(primitiveName);
49
49
  };
50
50
 
51
- // .angular-partial-tmp-4ueezp/src/core/streamingSlotRegistry.ts
51
+ // .angular-partial-tmp-L9oYfg/src/core/streamingSlotRegistry.ts
52
52
  var STREAMING_SLOT_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotAsyncLocalStorage");
53
53
  var isObjectRecord2 = (value) => Boolean(value) && typeof value === "object";
54
54
  var isAsyncLocalStorage = (value) => isObjectRecord2(value) && ("getStore" in value) && typeof value.getStore === "function" && ("run" in value) && typeof value.run === "function";
package/dist/build.js CHANGED
@@ -12860,11 +12860,32 @@ var isTestSourcePath = (file) => {
12860
12860
  };
12861
12861
 
12862
12862
  // node_modules/@absolutejs/sync/dist/client/index.js
12863
- var RUNTIME_TRANSPORT, host, isRegistry = (value) => typeof value === "object" && value !== null && Array.isArray(Reflect.get(value, "installations")), registry, SyncLocalStoreSchemaError, positiveVersion = (value, label) => {
12863
+ var RUNTIME_TRANSPORT, host, isRegistry = (value) => typeof value === "object" && value !== null && Array.isArray(Reflect.get(value, "installations")), registry, SyncLocalDataPolicyError, SyncLocalStoreSchemaError, positiveVersion = (value, label) => {
12864
12864
  if (!Number.isSafeInteger(value) || value < 1)
12865
12865
  throw new SyncLocalStoreSchemaError("INVALID_PLAN", `${label} must be a positive safe integer`);
12866
12866
  return value;
12867
- }, isSchemaBundle = (schema) => ("components" in schema), normalizeSyncLocalSchemaComponents = (schema = { version: 1 }) => {
12867
+ }, isSchemaBundle = (schema) => ("components" in schema), validatePolicyMatch = (match, label) => {
12868
+ if (match.length === 0 || match.trim() !== match || /^\*+$/.test(match) || match.includes("**"))
12869
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.match must be an exact name or a non-empty glob without adjacent wildcards.`);
12870
+ }, validateSyncLocalDataPolicy = (policy, label = "localData") => {
12871
+ if (policy.maxBytesPerNamespace !== undefined && (!Number.isSafeInteger(policy.maxBytesPerNamespace) || policy.maxBytesPerNamespace < 1))
12872
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.maxBytesPerNamespace must be a positive safe integer.`);
12873
+ for (const [index, rule] of (policy.collections ?? []).entries()) {
12874
+ validatePolicyMatch(rule.match, `${label}.collections[${index}]`);
12875
+ if (rule.maxAgeMs !== undefined && (!Number.isSafeInteger(rule.maxAgeMs) || rule.maxAgeMs < 1))
12876
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}].maxAgeMs must be a positive safe integer.`);
12877
+ if (rule.persistence === "memory-only" && rule.protection === "required")
12878
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}] cannot require at-rest protection when it is memory-only.`);
12879
+ if (rule.sensitivity !== undefined && rule.sensitivity !== "public" && rule.protection !== "required" && rule.persistence !== "memory-only")
12880
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.collections[${index}] declares ${rule.sensitivity} data without required protection or memory-only persistence.`);
12881
+ }
12882
+ for (const [index, rule] of (policy.mutations ?? []).entries()) {
12883
+ validatePolicyMatch(rule.match, `${label}.mutations[${index}]`);
12884
+ if (rule.sensitivity !== undefined && rule.sensitivity !== "public" && rule.protection !== "required" && rule.persistence !== "memory-only")
12885
+ throw new SyncLocalDataPolicyError("INVALID_POLICY", `${label}.mutations[${index}] declares ${rule.sensitivity} arguments without required protection.`);
12886
+ }
12887
+ return policy;
12888
+ }, normalizeSyncLocalSchemaComponents = (schema = { version: 1 }) => {
12868
12889
  const components = isSchemaBundle(schema) ? [...schema.components] : [{ ...schema, id: "@absolutejs/app" }];
12869
12890
  const ids = new Set;
12870
12891
  for (const component of components) {
@@ -12873,6 +12894,8 @@ var RUNTIME_TRANSPORT, host, isRegistry = (value) => typeof value === "object" &
12873
12894
  if (ids.has(component.id))
12874
12895
  throw new SyncLocalStoreSchemaError("INVALID_PLAN", `Sync schema component "${component.id}" is declared more than once`);
12875
12896
  ids.add(component.id);
12897
+ if (component.localData)
12898
+ validateSyncLocalDataPolicy(component.localData, `${component.id}.localData`);
12876
12899
  }
12877
12900
  return components.sort((a, b2) => a.id.localeCompare(b2.id));
12878
12901
  }, resolveSyncLocalSchemaComponents = (storedVersions, schema = { version: 1 }) => {
@@ -12930,6 +12953,14 @@ var init_client = __esm(() => {
12930
12953
  });
12931
12954
  return created;
12932
12955
  })();
12956
+ SyncLocalDataPolicyError = class SyncLocalDataPolicyError extends Error {
12957
+ code;
12958
+ constructor(code, message) {
12959
+ super(message);
12960
+ this.name = "SyncLocalDataPolicyError";
12961
+ this.code = code;
12962
+ }
12963
+ };
12933
12964
  SyncLocalStoreSchemaError = class SyncLocalStoreSchemaError extends Error {
12934
12965
  code;
12935
12966
  storedVersion;
@@ -12986,7 +13017,7 @@ var object = (value) => typeof value === "object" && value !== null && !Array.is
12986
13017
  if (!object(value))
12987
13018
  throw metadataError(id, detail);
12988
13019
  return value;
12989
- }, normalizeJsonValue = (value, id, field) => {
13020
+ }, unknownField = (record, key) => record[key], normalizeJsonValue = (value, id, field) => {
12990
13021
  if (value === null || typeof value === "string" || typeof value === "boolean")
12991
13022
  return value;
12992
13023
  if (typeof value === "number" && Number.isFinite(value))
@@ -13037,9 +13068,108 @@ var object = (value) => typeof value === "object" && value !== null && !Array.is
13037
13068
  operations: operations.map((entry, operationIndex) => operation(entry, id, operationIndex)),
13038
13069
  toVersion: positiveVersion2(Reflect.get(record, "toVersion"), id, `migration ${index}.toVersion`)
13039
13070
  };
13071
+ }, localDataPolicy = (value, id) => {
13072
+ const record = requireObject(value, id, "localData must be an object.");
13073
+ const allowed = new Set([
13074
+ "collections",
13075
+ "maxBytesPerNamespace",
13076
+ "mutations"
13077
+ ]);
13078
+ const unsupported = Object.keys(record).find((key) => !allowed.has(key));
13079
+ if (unsupported)
13080
+ throw metadataError(id, `localData.${unsupported} is not supported.`);
13081
+ const collectionRules = Reflect.get(record, "collections");
13082
+ const mutationRules = Reflect.get(record, "mutations");
13083
+ if (collectionRules !== undefined && !Array.isArray(collectionRules))
13084
+ throw metadataError(id, "localData.collections must be an array.");
13085
+ if (mutationRules !== undefined && !Array.isArray(mutationRules))
13086
+ throw metadataError(id, "localData.mutations must be an array.");
13087
+ const collections = Array.isArray(collectionRules) ? collectionRules.map((entry, index) => {
13088
+ const rule = requireObject(entry, id, `localData.collections[${index}] must be an object.`);
13089
+ const allowedRuleKeys = new Set([
13090
+ "evictionPriority",
13091
+ "match",
13092
+ "maxAgeMs",
13093
+ "onProtectionUnavailable",
13094
+ "persistence",
13095
+ "protection",
13096
+ "sensitivity"
13097
+ ]);
13098
+ const unsupportedRuleKey = Object.keys(rule).find((key) => !allowedRuleKeys.has(key));
13099
+ if (unsupportedRuleKey)
13100
+ throw metadataError(id, `localData.collections[${index}].${unsupportedRuleKey} is not supported.`);
13101
+ const match = nonEmpty(Reflect.get(rule, "match"), id, `localData.collections[${index}].match`);
13102
+ const persistence = unknownField(rule, "persistence");
13103
+ const sensitivity = unknownField(rule, "sensitivity");
13104
+ const protection = unknownField(rule, "protection");
13105
+ const onProtectionUnavailable = unknownField(rule, "onProtectionUnavailable");
13106
+ const evictionPriority = unknownField(rule, "evictionPriority");
13107
+ const maxAge = unknownField(rule, "maxAgeMs");
13108
+ if (persistence !== undefined && persistence !== "durable" && persistence !== "memory-only")
13109
+ throw metadataError(id, `localData.collections[${index}].persistence is invalid.`);
13110
+ if (sensitivity !== undefined && sensitivity !== "public" && sensitivity !== "private" && sensitivity !== "secret")
13111
+ throw metadataError(id, `localData.collections[${index}].sensitivity is invalid.`);
13112
+ if (protection !== undefined && protection !== "none" && protection !== "required")
13113
+ throw metadataError(id, `localData.collections[${index}].protection is invalid.`);
13114
+ if (onProtectionUnavailable !== undefined && onProtectionUnavailable !== "error" && onProtectionUnavailable !== "memory-only")
13115
+ throw metadataError(id, `localData.collections[${index}].onProtectionUnavailable is invalid.`);
13116
+ if (evictionPriority !== undefined && evictionPriority !== "critical" && evictionPriority !== "normal" && evictionPriority !== "disposable")
13117
+ throw metadataError(id, `localData.collections[${index}].evictionPriority is invalid.`);
13118
+ return {
13119
+ match,
13120
+ ...sensitivity ? { sensitivity } : {},
13121
+ ...persistence ? { persistence } : {},
13122
+ ...protection ? { protection } : {},
13123
+ ...onProtectionUnavailable ? {
13124
+ onProtectionUnavailable
13125
+ } : {},
13126
+ ...evictionPriority ? { evictionPriority } : {},
13127
+ ...maxAge === undefined ? {} : {
13128
+ maxAgeMs: positiveVersion2(maxAge, id, `localData.collections[${index}].maxAgeMs`)
13129
+ }
13130
+ };
13131
+ }) : undefined;
13132
+ const mutations = Array.isArray(mutationRules) ? mutationRules.map((entry, index) => {
13133
+ const rule = requireObject(entry, id, `localData.mutations[${index}] must be an object.`);
13134
+ const allowedRuleKeys = new Set([
13135
+ "match",
13136
+ "persistence",
13137
+ "protection",
13138
+ "sensitivity"
13139
+ ]);
13140
+ const unsupportedRuleKey = Object.keys(rule).find((key) => !allowedRuleKeys.has(key));
13141
+ if (unsupportedRuleKey)
13142
+ throw metadataError(id, `localData.mutations[${index}].${unsupportedRuleKey} is not supported.`);
13143
+ const protection = unknownField(rule, "protection");
13144
+ const sensitivity = unknownField(rule, "sensitivity");
13145
+ const persistence = unknownField(rule, "persistence");
13146
+ if (protection !== undefined && protection !== "none" && protection !== "required")
13147
+ throw metadataError(id, `localData.mutations[${index}].protection is invalid.`);
13148
+ if (sensitivity !== undefined && sensitivity !== "public" && sensitivity !== "private" && sensitivity !== "secret")
13149
+ throw metadataError(id, `localData.mutations[${index}].sensitivity is invalid.`);
13150
+ if (persistence !== undefined && persistence !== "durable" && persistence !== "memory-only")
13151
+ throw metadataError(id, `localData.mutations[${index}].persistence is invalid.`);
13152
+ return {
13153
+ match: nonEmpty(Reflect.get(rule, "match"), id, `localData.mutations[${index}].match`),
13154
+ ...sensitivity ? { sensitivity } : {},
13155
+ ...persistence ? {
13156
+ persistence
13157
+ } : {},
13158
+ ...protection ? { protection } : {}
13159
+ };
13160
+ }) : undefined;
13161
+ const quota = Reflect.get(record, "maxBytesPerNamespace");
13162
+ return {
13163
+ ...collections ? { collections } : {},
13164
+ ...mutations ? { mutations } : {},
13165
+ ...quota === undefined ? {} : {
13166
+ maxBytesPerNamespace: positiveVersion2(quota, id, "localData.maxBytesPerNamespace")
13167
+ }
13168
+ };
13040
13169
  }, component = (id, value) => {
13041
13170
  const record = requireObject(value, id, "localSchema must be an object.");
13042
13171
  const allowed = new Set([
13172
+ "localData",
13043
13173
  "migrations",
13044
13174
  "minimumCompatibleVersion",
13045
13175
  "version"
@@ -13051,11 +13181,13 @@ var object = (value) => typeof value === "object" && value !== null && !Array.is
13051
13181
  const declaredMinimum = Reflect.get(record, "minimumCompatibleVersion");
13052
13182
  const minimumCompatibleVersion = declaredMinimum === undefined ? Math.max(1, version - 2) : positiveVersion2(declaredMinimum, id, "minimumCompatibleVersion");
13053
13183
  const declaredMigrations = Reflect.get(record, "migrations");
13184
+ const declaredLocalData = Reflect.get(record, "localData");
13054
13185
  if (declaredMigrations !== undefined && !Array.isArray(declaredMigrations))
13055
13186
  throw metadataError(id, "migrations must be an array.");
13056
13187
  const migrations = Array.isArray(declaredMigrations) ? declaredMigrations : undefined;
13057
13188
  return {
13058
13189
  id,
13190
+ ...declaredLocalData === undefined ? {} : { localData: localDataPolicy(declaredLocalData, id) },
13059
13191
  minimumCompatibleVersion,
13060
13192
  ...Array.isArray(migrations) ? {
13061
13193
  migrations: migrations.map((entry, index) => migration(entry, id, index))
@@ -29883,5 +30015,5 @@ export {
29883
30015
  build
29884
30016
  };
29885
30017
 
29886
- //# debugId=452381297EE1F66D64756E2164756E21
30018
+ //# debugId=EC44DCC5E5B34B8F64756E2164756E21
29887
30019
  //# sourceMappingURL=build.js.map