@absolutejs/absolute 0.20.0-beta.87 → 0.20.0-beta.89

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.
@@ -21,21 +21,98 @@ import {
21
21
  createMobileAuthTransport,
22
22
  installAuthClientRuntimeTransport
23
23
  } from "@absolutejs/auth/client/mobile";
24
+ var MAX_CONSUMED_AUTH_LINKS = 8;
25
+ var AUTH_LINK_RECEIPTS_KEY = "absolutejs.auth.callback-receipts.v1";
26
+ var authLinkReceipt = async (url) => [
27
+ ...new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(url)))
28
+ ].map((byte) => byte.toString(16).padStart(2, "0")).join("");
29
+ var parseAuthLinkReceipts = (value) => {
30
+ if (!value)
31
+ return [];
32
+ try {
33
+ const parsed = JSON.parse(value);
34
+ return Array.isArray(parsed) ? parsed.filter((receipt) => typeof receipt === "string" && /^[a-f0-9]{64}$/u.test(receipt)) : [];
35
+ } catch {
36
+ return [];
37
+ }
38
+ };
39
+ var createAbsoluteMobileAuthLinks = (provider = links, storage) => {
40
+ const consumed = new Set;
41
+ const delivered = new Set;
42
+ let operation = Promise.resolve();
43
+ const serialize = (run) => {
44
+ const result = operation.then(run, run);
45
+ operation = result.then(() => {
46
+ return;
47
+ }, () => {
48
+ return;
49
+ });
50
+ return result;
51
+ };
52
+ const consume = (url) => serialize(async () => {
53
+ const receipt = await authLinkReceipt(url);
54
+ if (consumed.has(receipt))
55
+ return false;
56
+ consumed.add(receipt);
57
+ if (consumed.size > MAX_CONSUMED_AUTH_LINKS) {
58
+ const oldest = consumed.values().next().value;
59
+ if (oldest)
60
+ consumed.delete(oldest);
61
+ }
62
+ if (storage && parseAuthLinkReceipts(await storage.get(AUTH_LINK_RECEIPTS_KEY).catch(() => null)).includes(receipt))
63
+ return false;
64
+ delivered.add(receipt);
65
+ return true;
66
+ });
67
+ return {
68
+ openExternal: provider.openExternal,
69
+ commitConsumed: () => serialize(async () => {
70
+ if (!storage || delivered.size === 0)
71
+ return;
72
+ const existing = parseAuthLinkReceipts(await storage.get(AUTH_LINK_RECEIPTS_KEY).catch(() => null));
73
+ const receipts = [
74
+ ...new Set([...existing, ...delivered])
75
+ ].slice(-MAX_CONSUMED_AUTH_LINKS);
76
+ await storage.set(AUTH_LINK_RECEIPTS_KEY, JSON.stringify(receipts));
77
+ }),
78
+ getLaunchUrl: async () => {
79
+ const url = await provider.getLaunchUrl();
80
+ return url && await consume(url) ? url : null;
81
+ },
82
+ onOpen: (listener) => provider.onOpen((url) => {
83
+ consume(url).then((accepted) => {
84
+ if (accepted)
85
+ listener(url);
86
+ });
87
+ })
88
+ };
89
+ };
24
90
  var createAbsoluteMobileShellAuth = async (config, options = {}) => {
91
+ const authLinks = createAbsoluteMobileAuthLinks(links, secureStorage);
25
92
  const client = createMobileAuthClient({
26
93
  allowedOrigins: [config.issuer],
27
94
  beforeSignOut: options.beforeSignOut,
28
95
  clientId: config.clientId,
29
96
  issuer: config.issuer,
30
97
  lifecycle,
31
- links,
98
+ links: authLinks,
32
99
  redirectUri: config.redirectUri,
33
100
  resource: config.issuer,
34
101
  scopes: config.scopes,
35
102
  storage: secureStorage
36
103
  });
104
+ client.onPrincipalChange((next) => {
105
+ if (next)
106
+ authLinks.commitConsumed().catch(() => {
107
+ return;
108
+ });
109
+ });
37
110
  await client.start();
38
111
  const principal = await client.principal();
112
+ if (principal)
113
+ await authLinks.commitConsumed().catch(() => {
114
+ return;
115
+ });
39
116
  installAuthClientRuntimeTransport(createMobileAuthTransport(client, { baseUrl: config.issuer }));
40
117
  return {
41
118
  clientId: config.clientId,
@@ -48,5 +125,6 @@ var createAbsoluteMobileShellAuth = async (config, options = {}) => {
48
125
  };
49
126
  };
50
127
  export {
128
+ createAbsoluteMobileAuthLinks,
51
129
  createAbsoluteMobileShellAuth
52
130
  };
@@ -605,12 +605,50 @@ var removeStaging = async (releaseId) => {
605
605
  return;
606
606
  });
607
607
  };
608
+ var isExistingDirectoryError = (error) => typeof error === "object" && error !== null && Reflect.get(error, "code") === "OS-PLUG-FILE-0010";
609
+ var ensureDirectory = async (path) => {
610
+ try {
611
+ await Filesystem.mkdir({
612
+ directory: Directory.Library,
613
+ path,
614
+ recursive: true
615
+ });
616
+ } catch (error) {
617
+ if (!isExistingDirectoryError(error))
618
+ throw error;
619
+ }
620
+ };
621
+ var parentDirectories = (manifest) => {
622
+ const directories = manifest.files.flatMap((file) => {
623
+ const segments = file.path.split("/").slice(0, -1);
624
+ return segments.map((_, index) => segments.slice(0, index + 1).join("/"));
625
+ });
626
+ return [...new Set(directories)];
627
+ };
628
+ var ensureDirectoryPairs = async (directories, release, partial, index = 0) => {
629
+ const directory = directories[index];
630
+ if (!directory)
631
+ return;
632
+ await ensureDirectory(`${release}/${directory}`);
633
+ await ensureDirectory(`${partial}/${directory}`);
634
+ await ensureDirectoryPairs(directories, release, partial, index + 1);
635
+ };
636
+ var ensureTransactionDirectories = async (manifest) => {
637
+ const release = releasePath(manifest.releaseId);
638
+ const partial = `${STAGING_ROOT}/${manifest.releaseId}`;
639
+ await ensureDirectory(release);
640
+ await ensureDirectory(partial);
641
+ await ensureDirectoryPairs(parentDirectories(manifest), release, partial);
642
+ };
608
643
  var filesystemBytes = async (data) => typeof data === "string" ? base64Bytes(data) : new Uint8Array(await data.arrayBuffer());
609
644
  var createStore = () => {
645
+ let reusableRelease;
610
646
  let staging;
647
+ let resuming = false;
611
648
  return {
612
649
  abort: async (releaseId) => {
613
650
  staging = undefined;
651
+ resuming = false;
614
652
  await removeRelease(releaseId);
615
653
  await removeStaging(releaseId);
616
654
  const persisted = await readStaging();
@@ -682,6 +720,7 @@ var createStore = () => {
682
720
  });
683
721
  },
684
722
  begin: async (manifest) => {
723
+ reusableRelease = (await readState()).activeRelease;
685
724
  const persisted = await readStaging();
686
725
  const resume = persisted?.releaseId === manifest.releaseId && persisted.signature.keyId === manifest.signature.keyId && persisted.signature.value === manifest.signature.value;
687
726
  if (persisted && !resume)
@@ -693,16 +732,13 @@ var createStore = () => {
693
732
  await removeRelease(manifest.releaseId);
694
733
  await removeStaging(manifest.releaseId);
695
734
  }
696
- await Filesystem.mkdir({
697
- directory: Directory.Library,
698
- path: releasePath(manifest.releaseId),
699
- recursive: true
700
- });
735
+ await ensureTransactionDirectories(manifest);
701
736
  await Preferences.set({
702
737
  key: STAGING_KEY,
703
738
  value: JSON.stringify(manifest)
704
739
  });
705
740
  staging = manifest;
741
+ resuming = resume;
706
742
  },
707
743
  commit: async (manifest) => {
708
744
  if (staging?.releaseId !== manifest.releaseId)
@@ -717,9 +753,10 @@ var createStore = () => {
717
753
  await removeStaging(manifest.releaseId);
718
754
  await Preferences.remove({ key: STAGING_KEY });
719
755
  staging = undefined;
756
+ resuming = false;
720
757
  },
721
758
  readPartial: async (file) => {
722
- if (!staging)
759
+ if (!staging || !resuming)
723
760
  return null;
724
761
  const result = await Filesystem.readFile({
725
762
  directory: Directory.Library,
@@ -728,17 +765,16 @@ var createStore = () => {
728
765
  return result ? filesystemBytes(result.data).catch(() => null) : null;
729
766
  },
730
767
  readReusable: async (file) => {
731
- const state = await readState();
732
- if (!state.activeRelease)
768
+ if (!reusableRelease)
733
769
  return null;
734
770
  const result = await Filesystem.readFile({
735
771
  directory: Directory.Library,
736
- path: `${releasePath(state.activeRelease)}/${file.path}`
772
+ path: `${releasePath(reusableRelease)}/${file.path}`
737
773
  }).catch(() => null);
738
774
  return result ? filesystemBytes(result.data).catch(() => null) : null;
739
775
  },
740
776
  readStaged: async (file) => {
741
- if (!staging)
777
+ if (!staging || !resuming)
742
778
  return null;
743
779
  const result = await Filesystem.readFile({
744
780
  directory: Directory.Library,
@@ -747,8 +783,10 @@ var createStore = () => {
747
783
  return result ? filesystemBytes(result.data).catch(() => null) : null;
748
784
  },
749
785
  suspend: async (releaseId) => {
750
- if (staging?.releaseId === releaseId)
786
+ if (staging?.releaseId === releaseId) {
751
787
  staging = undefined;
788
+ resuming = false;
789
+ }
752
790
  },
753
791
  write: async (file, contents) => {
754
792
  if (!staging || !staging.files.some((candidate) => candidate.path === file.path))
@@ -876,6 +914,7 @@ var installAbsoluteMobileShellUpdates = async (manifest) => {
876
914
  const recovered = await consumeNativeRecovery(initial, reportFor(initial));
877
915
  const state = await reconcilePendingRelease(store, recovered, reportFor(recovered));
878
916
  const client = createAbsoluteMobileUpdateClient({
917
+ concurrency: 6,
879
918
  config: clientConfig(state),
880
919
  store,
881
920
  verifier: createVerifier(updates.publicKeys),
@@ -1,6 +1,13 @@
1
+ import { links, secureStorage } from '@absolutejs/devices';
1
2
  import { type MobileAuthPrincipal } from '@absolutejs/auth/client/mobile';
2
3
  import type { AbsoluteMobileAuthManifest } from './nativeAuth';
3
4
  import type { AbsoluteMobileFetch } from './transport';
5
+ type AbsoluteMobileAuthLinks = Pick<typeof links, 'getLaunchUrl' | 'onOpen' | 'openExternal'>;
6
+ type AbsoluteMobileAuthLinkReceiptStorage = Pick<typeof secureStorage, 'get' | 'set'>;
7
+ type AbsoluteMobileAuthLinkBoundary = AbsoluteMobileAuthLinks & {
8
+ commitConsumed: () => Promise<void>;
9
+ };
10
+ export declare const createAbsoluteMobileAuthLinks: (provider?: AbsoluteMobileAuthLinks, storage?: AbsoluteMobileAuthLinkReceiptStorage) => AbsoluteMobileAuthLinkBoundary;
4
11
  export type AbsoluteMobileShellAuth = {
5
12
  clientId: string;
6
13
  fetch: AbsoluteMobileFetch;
@@ -13,3 +20,4 @@ export type AbsoluteMobileShellAuth = {
13
20
  export declare const createAbsoluteMobileShellAuth: (config: AbsoluteMobileAuthManifest, options?: {
14
21
  beforeSignOut?: () => Promise<void> | void;
15
22
  }) => Promise<AbsoluteMobileShellAuth>;
23
+ export {};
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "dependencies": {
10
10
  "@absolutejs/auth": ">=0.75.0 <0.77.0",
11
11
  "@absolutejs/beacon": ">=0.7.0-beta.4 <0.8.0",
12
- "@absolutejs/deploy": "0.25.13",
12
+ "@absolutejs/deploy": "0.25.14",
13
13
  "@absolutejs/devices": "0.7.0",
14
14
  "@absolutejs/devices-capacitor": "0.8.0",
15
15
  "@absolutejs/devices-expo": "0.0.2",
@@ -33,6 +33,7 @@
33
33
  "description": "A fullstack meta-framework for building web applications with TypeScript",
34
34
  "devDependencies": {
35
35
  "@absolutejs/blob": "0.5.2",
36
+ "@absolutejs/changelog": "^0.6.0",
36
37
  "@absolutejs/dispatch": "0.9.0",
37
38
  "@absolutejs/manifest": "0.9.0",
38
39
  "@absolutejs/scoped-state": "0.2.2",
@@ -295,10 +296,12 @@
295
296
  }
296
297
  },
297
298
  "files": [
298
- "dist",
299
+ "CHANGELOG.md",
299
300
  "LICENSE",
300
301
  "README.md",
301
- "THIRD_PARTY_NOTICES.md"
302
+ "THIRD_PARTY_NOTICES.md",
303
+ "changelog.json",
304
+ "dist"
302
305
  ],
303
306
  "homepage": "https://github.com/absolutejs/absolutejs",
304
307
  "license": "BSL-1.1",
@@ -443,6 +446,7 @@
443
446
  "scripts": {
444
447
  "bd": "bun run scripts/build.ts && bun",
445
448
  "build": "bun run scripts/build.ts",
449
+ "check:package": "absolute-changelog check",
446
450
  "config": "bun run src/cli/index.ts config",
447
451
  "config:studio": "bun run src/cli/index.ts config --config example/absolute.config.ts",
448
452
  "db:push": "drizzle-kit push",
@@ -452,6 +456,7 @@
452
456
  "format:check": "bun run src/cli/index.ts prettier --check",
453
457
  "lint": "bun run src/cli/index.ts eslint",
454
458
  "ls": "bun run src/cli/index.ts ls",
459
+ "prepublishOnly": "bun run check:package",
455
460
  "release": "bun run release:gate && bun publish",
456
461
  "release:beta": "bun run release:gate && bun publish --tag beta",
457
462
  "release:gate": "bun run scripts/releaseGate.ts",
@@ -523,7 +528,7 @@
523
528
  ]
524
529
  }
525
530
  },
526
- "version": "0.20.0-beta.87",
531
+ "version": "0.20.0-beta.89",
527
532
  "workspaces": [
528
533
  "tests/fixtures/*",
529
534
  "tests/fixtures/_packages/*"