@symbiote-native/sqlite 0.1.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 (128) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +283 -0
  3. package/build/angular/index.d.ts +2 -0
  4. package/build/angular/index.js +2 -0
  5. package/build/angular/sqlite.service.d.ts +41 -0
  6. package/build/angular/sqlite.service.js +127 -0
  7. package/build/core/index.d.ts +10 -0
  8. package/build/core/index.js +6 -0
  9. package/build/core/native-database.d.ts +65 -0
  10. package/build/core/native-database.js +13 -0
  11. package/build/core/native-module.d.ts +25 -0
  12. package/build/core/native-module.js +17 -0
  13. package/build/core/native-session.d.ts +20 -0
  14. package/build/core/native-session.js +1 -0
  15. package/build/core/native-statement.d.ts +45 -0
  16. package/build/core/native-statement.js +6 -0
  17. package/build/core/param-utils.d.ts +28 -0
  18. package/build/core/param-utils.js +126 -0
  19. package/build/core/path-utils.d.ts +6 -0
  20. package/build/core/path-utils.js +29 -0
  21. package/build/core/query-utils.d.ts +17 -0
  22. package/build/core/query-utils.js +37 -0
  23. package/build/core/sqlite-database.d.ts +246 -0
  24. package/build/core/sqlite-database.js +427 -0
  25. package/build/core/sqlite-session.d.ts +84 -0
  26. package/build/core/sqlite-session.js +121 -0
  27. package/build/core/sqlite-statement.d.ts +96 -0
  28. package/build/core/sqlite-statement.js +321 -0
  29. package/build/core/sqlite-tagged-query.d.ts +73 -0
  30. package/build/core/sqlite-tagged-query.js +119 -0
  31. package/build/core/storage.d.ts +107 -0
  32. package/build/core/storage.js +382 -0
  33. package/build/core/types.d.ts +30 -0
  34. package/build/core/types.js +1 -0
  35. package/build/react/index.d.ts +2 -0
  36. package/build/react/index.js +2 -0
  37. package/build/react/sqlite-context.d.ts +25 -0
  38. package/build/react/sqlite-context.js +129 -0
  39. package/build/solid/index.d.ts +2 -0
  40. package/build/solid/index.js +2 -0
  41. package/build/solid/sqlite-context.d.ts +23 -0
  42. package/build/solid/sqlite-context.js +106 -0
  43. package/build/svelte/SQLiteProvider.svelte +88 -0
  44. package/build/svelte/SQLiteProvider.svelte.d.ts +13 -0
  45. package/build/svelte/index.d.ts +3 -0
  46. package/build/svelte/index.js +5 -0
  47. package/build/svelte/sqlite-context.d.ts +11 -0
  48. package/build/svelte/sqlite-context.js +23 -0
  49. package/build/vue/index.d.ts +2 -0
  50. package/build/vue/index.js +2 -0
  51. package/build/vue/sqlite-context.d.ts +21 -0
  52. package/build/vue/sqlite-context.js +69 -0
  53. package/build-ngc/angular/index.d.ts +2 -0
  54. package/build-ngc/angular/index.js +3 -0
  55. package/build-ngc/angular/index.js.map +1 -0
  56. package/build-ngc/angular/sqlite.service.d.ts +44 -0
  57. package/build-ngc/angular/sqlite.service.js +85 -0
  58. package/build-ngc/angular/sqlite.service.js.map +1 -0
  59. package/build-ngc/core/index.d.ts +10 -0
  60. package/build-ngc/core/index.js +7 -0
  61. package/build-ngc/core/index.js.map +1 -0
  62. package/build-ngc/core/native-database.d.ts +65 -0
  63. package/build-ngc/core/native-database.js +14 -0
  64. package/build-ngc/core/native-database.js.map +1 -0
  65. package/build-ngc/core/native-module.d.ts +25 -0
  66. package/build-ngc/core/native-module.js +18 -0
  67. package/build-ngc/core/native-module.js.map +1 -0
  68. package/build-ngc/core/native-session.d.ts +20 -0
  69. package/build-ngc/core/native-session.js +2 -0
  70. package/build-ngc/core/native-session.js.map +1 -0
  71. package/build-ngc/core/native-statement.d.ts +45 -0
  72. package/build-ngc/core/native-statement.js +7 -0
  73. package/build-ngc/core/native-statement.js.map +1 -0
  74. package/build-ngc/core/param-utils.d.ts +28 -0
  75. package/build-ngc/core/param-utils.js +127 -0
  76. package/build-ngc/core/param-utils.js.map +1 -0
  77. package/build-ngc/core/path-utils.d.ts +6 -0
  78. package/build-ngc/core/path-utils.js +30 -0
  79. package/build-ngc/core/path-utils.js.map +1 -0
  80. package/build-ngc/core/query-utils.d.ts +17 -0
  81. package/build-ngc/core/query-utils.js +38 -0
  82. package/build-ngc/core/query-utils.js.map +1 -0
  83. package/build-ngc/core/sqlite-database.d.ts +246 -0
  84. package/build-ngc/core/sqlite-database.js +428 -0
  85. package/build-ngc/core/sqlite-database.js.map +1 -0
  86. package/build-ngc/core/sqlite-session.d.ts +84 -0
  87. package/build-ngc/core/sqlite-session.js +122 -0
  88. package/build-ngc/core/sqlite-session.js.map +1 -0
  89. package/build-ngc/core/sqlite-statement.d.ts +96 -0
  90. package/build-ngc/core/sqlite-statement.js +322 -0
  91. package/build-ngc/core/sqlite-statement.js.map +1 -0
  92. package/build-ngc/core/sqlite-tagged-query.d.ts +73 -0
  93. package/build-ngc/core/sqlite-tagged-query.js +120 -0
  94. package/build-ngc/core/sqlite-tagged-query.js.map +1 -0
  95. package/build-ngc/core/storage.d.ts +107 -0
  96. package/build-ngc/core/storage.js +383 -0
  97. package/build-ngc/core/storage.js.map +1 -0
  98. package/build-ngc/core/types.d.ts +30 -0
  99. package/build-ngc/core/types.js +2 -0
  100. package/build-ngc/core/types.js.map +1 -0
  101. package/native-link.json +12 -0
  102. package/package.json +141 -0
  103. package/src/angular/index.ts +2 -0
  104. package/src/angular/sqlite.service.ts +114 -0
  105. package/src/core/index.ts +40 -0
  106. package/src/core/native-database.ts +118 -0
  107. package/src/core/native-module.ts +57 -0
  108. package/src/core/native-session.ts +64 -0
  109. package/src/core/native-statement.ts +85 -0
  110. package/src/core/param-utils.ts +163 -0
  111. package/src/core/path-utils.ts +38 -0
  112. package/src/core/query-utils.ts +45 -0
  113. package/src/core/sqlite-database.ts +676 -0
  114. package/src/core/sqlite-session.ts +165 -0
  115. package/src/core/sqlite-statement.ts +578 -0
  116. package/src/core/sqlite-tagged-query.ts +160 -0
  117. package/src/core/storage.ts +492 -0
  118. package/src/core/types.ts +33 -0
  119. package/src/react/index.ts +2 -0
  120. package/src/react/sqlite-context.tsx +244 -0
  121. package/src/solid/index.ts +2 -0
  122. package/src/solid/sqlite-context.ts +156 -0
  123. package/src/svelte/SQLiteProvider.svelte +88 -0
  124. package/src/svelte/index.ts +6 -0
  125. package/src/svelte/sqlite-context.ts +32 -0
  126. package/src/svelte/svelte-compile.test-helper.ts +135 -0
  127. package/src/vue/index.ts +2 -0
  128. package/src/vue/sqlite-context.ts +105 -0
@@ -0,0 +1,2 @@
1
+ export * from '../core';
2
+ export * from './sqlite-context';
@@ -0,0 +1,2 @@
1
+ export * from '../core/index.js';
2
+ export * from './sqlite-context.js';
@@ -0,0 +1,23 @@
1
+ import { type JSX } from 'solid-js';
2
+ import { type IOnInitCallback, type ISQLiteOpenOptions, type SQLiteDatabase } from '../core';
3
+ export type ISQLiteProviderProps = {
4
+ /** The name of the database file to open. */
5
+ databaseName: string;
6
+ /** The directory where the database file is located. @default defaultDatabaseDirectory */
7
+ directory?: string;
8
+ /** Open options. */
9
+ options?: ISQLiteOpenOptions;
10
+ /** The children to render. */
11
+ children: JSX.Element;
12
+ /** Run once, right after the native handle opens and before children render. */
13
+ onInit?: IOnInitCallback;
14
+ /** Handle errors from SQLiteProvider. @default rethrow (propagate through Solid's error context) */
15
+ onError?: (error: Error) => void;
16
+ };
17
+ /**
18
+ * Context.Provider component that provides a SQLite database to all children. All descendants
19
+ * of this component can access the database via `useSQLiteContext`.
20
+ */
21
+ export declare function SQLiteProvider(props: ISQLiteProviderProps): JSX.Element;
22
+ /** A primitive for accessing the SQLite database provided by an ancestor `<SQLiteProvider>`. */
23
+ export declare function useSQLiteContext(): SQLiteDatabase;
@@ -0,0 +1,106 @@
1
+ // Solid <SQLiteProvider> + useSQLiteContext(), ported from expo-sqlite's hooks.tsx (sdk-57,
2
+ // .vendors/expo) onto this package's own openDatabaseAsync/SQLiteDatabase — see ../react's
3
+ // sqlite-context.tsx for the React twin this mirrors the OBSERVABLE contract of (the React-only
4
+ // mechanics, useEffect/use()/Suspense, don't transfer).
5
+ //
6
+ // Plain `.ts`, no JSX: this package's tsconfig has no per-directory override and inherits the
7
+ // root `jsx: "react-jsx"` (set for the React entry), so a `.tsx` file here would type-check its
8
+ // JSX against React's JSX namespace, not Solid's — the same trap `solid-jsx-namespace.md`
9
+ // documents for the adapter itself. `createComponent` is called directly instead, exactly as
10
+ // `packages/navigation/src/solid/stack/index.ts` does throughout.
11
+ //
12
+ // createResource is the right tool: it natively models pending/error/ready, and — the load-bearing
13
+ // part — reading an ERRORED resource accessor THROWS SYNCHRONOUSLY on every read (solid-js's own
14
+ // `read()`: `if (err !== undefined && !pr) throw err`), tracked or not. That is Solid's real
15
+ // equivalent of upstream's `handler = (e) => { throw e }` default: no onError -> the throw surfaces
16
+ // wherever `db()` is read (here, inside <Show>'s own tracking), and propagates through Solid's
17
+ // error-context chain exactly like any other component/memo/effect throw in this adapter
18
+ // (adapters/solid/src/render.ts's `catchError` + rethrow at the mount root — the tested,
19
+ // established "unhandled async failure" convention for this Solid adapter). With onError present,
20
+ // the fetcher calls it and resolves to `undefined` instead of throwing, so <Show> simply renders
21
+ // nothing rather than propagating — matching upstream's "loading || !db -> render null" forever.
22
+ //
23
+ // Closing the previous database before opening the next reuses createResource's own
24
+ // ResourceFetcherInfo.value (the last successfully resolved value) rather than a second piece of
25
+ // state — it IS "the database this resource had opened before". `openedDb` is a plain closure
26
+ // variable (not read through the resource accessor) so `onCleanup` never has to read a possibly
27
+ // -errored resource, which would itself throw during teardown.
28
+ //
29
+ // assetSource is deliberately NOT ported: it needs expo-asset, out of scope (see the README).
30
+ // useSuspense is deliberately NOT offered: Solid's own <Suspense> already composes with a plain
31
+ // createResource-backed component with zero extra code (any ancestor <Suspense> defers on this
32
+ // resource for free), so there is no second, opt-in code path to build the way React needs one —
33
+ // <prop_types_split_agnostic_vs_per_adapter>'s "framework-idiom divergence" class of omission.
34
+ import { createComponent, createContext, createResource, onCleanup, useContext, } from 'solid-js';
35
+ import { Show } from 'solid-js';
36
+ import { openDatabaseAsync, } from '../core/index.js';
37
+ const SQLiteContext = createContext();
38
+ function toError(cause) {
39
+ return cause instanceof Error ? cause : new Error(String(cause));
40
+ }
41
+ /**
42
+ * Context.Provider component that provides a SQLite database to all children. All descendants
43
+ * of this component can access the database via `useSQLiteContext`.
44
+ */
45
+ export function SQLiteProvider(props) {
46
+ // The last database THIS provider successfully opened — read only by onCleanup, never through
47
+ // the resource accessor (which throws when the resource is in its errored state).
48
+ let openedDb;
49
+ const [db] = createResource(() => ({
50
+ databaseName: props.databaseName,
51
+ directory: props.directory,
52
+ options: props.options,
53
+ onInit: props.onInit,
54
+ }), async (source, info) => {
55
+ if (info.value !== undefined) {
56
+ await info.value.closeAsync();
57
+ }
58
+ try {
59
+ const opened = await openDatabaseAsync(source.databaseName, { ...source.options, onInit: source.onInit }, source.directory);
60
+ openedDb = opened;
61
+ return opened;
62
+ }
63
+ catch (cause) {
64
+ openedDb = undefined;
65
+ const error = toError(cause);
66
+ if (props.onError !== undefined) {
67
+ props.onError(error);
68
+ return undefined;
69
+ }
70
+ throw error;
71
+ }
72
+ });
73
+ onCleanup(() => {
74
+ void openedDb?.closeAsync();
75
+ });
76
+ function renderReady(database) {
77
+ return createComponent(SQLiteContext.Provider, {
78
+ get value() {
79
+ return database();
80
+ },
81
+ get children() {
82
+ return props.children;
83
+ },
84
+ });
85
+ }
86
+ // A direct call, not createComponent(Show, …): Show is overloaded (keyed vs non-keyed), and
87
+ // TypeScript resolves an overloaded value against createComponent's generic Component<T> by its
88
+ // LAST signature only — reporting the non-keyed props object as missing `keyed: true`. Calling
89
+ // it directly goes through normal overload resolution instead, which picks correctly. Show's own
90
+ // body needs no extra untrack wrapping (it already wraps every read in its own createMemo), so
91
+ // nothing behavioral is lost by skipping createComponent here.
92
+ return Show({
93
+ get when() {
94
+ return db();
95
+ },
96
+ children: renderReady,
97
+ });
98
+ }
99
+ /** A primitive for accessing the SQLite database provided by an ancestor `<SQLiteProvider>`. */
100
+ export function useSQLiteContext() {
101
+ const context = useContext(SQLiteContext);
102
+ if (context === undefined) {
103
+ throw new Error('useSQLiteContext must be used within a <SQLiteProvider>');
104
+ }
105
+ return context;
106
+ }
@@ -0,0 +1,88 @@
1
+ <script lang="ts">
2
+ // SQLiteProvider: the Svelte equivalent of upstream expo-sqlite's SQLiteProvider/
3
+ // useSQLiteContext pair (.vendors/expo packages/expo-sqlite/src/hooks.tsx, sdk-57). Opens the
4
+ // database in an `$effect` (re-running whenever databaseName/directory/options/onInit change —
5
+ // $effect's own cleanup-then-rerun IS upstream's teardown()-then-setup() dance), renders
6
+ // nothing until it resolves, and hands the resolved `SQLiteDatabase` to descendants via
7
+ // `useSQLiteContext` (./sqlite-context).
8
+ //
9
+ // Context is provided through a BOXED GETTER set synchronously during init, mirroring
10
+ // navigation-context.ts: setContext only works at component-init time, but the database
11
+ // resolves later, so the getter is handed out immediately and its underlying `$state` is
12
+ // written once the effect settles.
13
+ //
14
+ // Deliberately excludes `assetSource` (needs `expo-asset`, out of scope for this package — see
15
+ // the core layer's own IOnInitCallback doc comment) and `useSuspense` (Svelte has no built-in
16
+ // Suspense primitive).
17
+ //
18
+ // Unlike upstream, `onInit` is not called from here — this package's own `openDatabaseAsync`
19
+ // already runs it internally before resolving (see `IOnInitCallback`'s doc comment in
20
+ // `core/types.ts`), so this component only forwards it through `options`.
21
+ import type { Snippet } from 'svelte';
22
+ import { openDatabaseAsync } from '../core';
23
+ import type { IOnInitCallback, ISQLiteOpenOptions, SQLiteDatabase } from '../core';
24
+ import { setSQLiteContext } from './sqlite-context';
25
+
26
+ let {
27
+ databaseName,
28
+ directory,
29
+ options,
30
+ onInit,
31
+ onError,
32
+ children,
33
+ }: {
34
+ databaseName: string;
35
+ directory?: string;
36
+ options?: ISQLiteOpenOptions;
37
+ onInit?: IOnInitCallback;
38
+ onError?: (error: Error) => void;
39
+ children?: Snippet;
40
+ } = $props();
41
+
42
+ let db = $state<SQLiteDatabase | undefined>(undefined);
43
+
44
+ setSQLiteContext({
45
+ get current(): SQLiteDatabase | undefined {
46
+ return db;
47
+ },
48
+ });
49
+
50
+ $effect(() => {
51
+ const name = databaseName;
52
+ const dir = directory;
53
+ const openOptions = options;
54
+ const init = onInit;
55
+
56
+ let cancelled = false;
57
+ let opened: SQLiteDatabase | undefined;
58
+
59
+ openDatabaseAsync(name, { ...openOptions, onInit: init }, dir)
60
+ .then(database => {
61
+ if (cancelled) {
62
+ void database.closeAsync();
63
+ return;
64
+ }
65
+ opened = database;
66
+ db = database;
67
+ })
68
+ .catch((error: unknown) => {
69
+ if (cancelled) return;
70
+ const err = error instanceof Error ? error : new Error(String(error));
71
+ // Upstream default: rethrow. Svelte has no error-boundary equivalent to catch a
72
+ // synchronous throw from here, so "rethrow" surfaces as an unhandled rejection — the
73
+ // same observable failure (an uncaught error) upstream produces without `onError`.
74
+ if (onError) onError(err);
75
+ else throw err;
76
+ });
77
+
78
+ return () => {
79
+ cancelled = true;
80
+ db = undefined;
81
+ if (opened) void opened.closeAsync();
82
+ };
83
+ });
84
+ </script>
85
+
86
+ {#if db}
87
+ {@render children?.()}
88
+ {/if}
@@ -0,0 +1,13 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { IOnInitCallback, ISQLiteOpenOptions } from '../core';
3
+ type $$ComponentProps = {
4
+ databaseName: string;
5
+ directory?: string;
6
+ options?: ISQLiteOpenOptions;
7
+ onInit?: IOnInitCallback;
8
+ onError?: (error: Error) => void;
9
+ children?: Snippet;
10
+ };
11
+ declare const SQLiteProvider: import("svelte").Component<$$ComponentProps, {}, "">;
12
+ type SQLiteProvider = ReturnType<typeof SQLiteProvider>;
13
+ export default SQLiteProvider;
@@ -0,0 +1,3 @@
1
+ export * from '../core';
2
+ export { default as SQLiteProvider } from './SQLiteProvider.svelte';
3
+ export * from './sqlite-context';
@@ -0,0 +1,5 @@
1
+ // @symbiote-native/sqlite/svelte: SQLiteProvider + useSQLiteContext over the framework-agnostic
2
+ // core. Mirrors packages/navigation/src/svelte/index.ts's barrel shape for a `.svelte` component.
3
+ export * from '../core/index.js';
4
+ export { default as SQLiteProvider } from './SQLiteProvider.svelte';
5
+ export * from './sqlite-context.js';
@@ -0,0 +1,11 @@
1
+ import type { SQLiteDatabase } from '../core';
2
+ export type ISQLiteContextValue = {
3
+ readonly current: SQLiteDatabase | undefined;
4
+ };
5
+ export declare function setSQLiteContext(value: ISQLiteContextValue): void;
6
+ /**
7
+ * A global function for accessing the SQLite database provided by the nearest ancestor
8
+ * `<SQLiteProvider>`. Throws if called outside one — matching upstream expo-sqlite's
9
+ * `useSQLiteContext` (`.vendors/expo` packages/expo-sqlite/src/hooks.tsx, sdk-57).
10
+ */
11
+ export declare function useSQLiteContext(): SQLiteDatabase;
@@ -0,0 +1,23 @@
1
+ // Svelte context accessor for the database `<SQLiteProvider>` opens. Mirrors
2
+ // packages/navigation/src/svelte/navigation-context.ts's boxed-getter shape: Svelte's
3
+ // setContext only runs synchronously during component init, while the database resolves later
4
+ // (an async openDatabaseAsync), so the provider hands out a getter object up front and mutates
5
+ // the value it reads later instead of calling setContext once resolution finishes.
6
+ import { getContext, setContext } from 'svelte';
7
+ const SQLITE_CONTEXT_KEY = Symbol('symbiote-sqlite-context');
8
+ // Written only from <SQLiteProvider>'s own init, never by app code.
9
+ export function setSQLiteContext(value) {
10
+ setContext(SQLITE_CONTEXT_KEY, value);
11
+ }
12
+ /**
13
+ * A global function for accessing the SQLite database provided by the nearest ancestor
14
+ * `<SQLiteProvider>`. Throws if called outside one — matching upstream expo-sqlite's
15
+ * `useSQLiteContext` (`.vendors/expo` packages/expo-sqlite/src/hooks.tsx, sdk-57).
16
+ */
17
+ export function useSQLiteContext() {
18
+ const value = getContext(SQLITE_CONTEXT_KEY);
19
+ if (value === undefined || value.current === undefined) {
20
+ throw new Error('useSQLiteContext must be used within a <SQLiteProvider>');
21
+ }
22
+ return value.current;
23
+ }
@@ -0,0 +1,2 @@
1
+ export * from '../core';
2
+ export * from './sqlite-context';
@@ -0,0 +1,2 @@
1
+ export * from '../core/index.js';
2
+ export * from './sqlite-context.js';
@@ -0,0 +1,21 @@
1
+ import type { ISQLiteOpenOptions, SQLiteDatabase } from '../core';
2
+ export type ISQLiteProviderProps = {
3
+ databaseName: string;
4
+ directory?: string;
5
+ options?: ISQLiteOpenOptions;
6
+ onInit?: (db: SQLiteDatabase) => Promise<void> | void;
7
+ onError?: (error: Error) => void;
8
+ };
9
+ /**
10
+ * Opens `databaseName` (re-opening whenever `databaseName`/`directory`/`options`/`onInit`
11
+ * change) and provides the resulting `SQLiteDatabase` to its default-slot children via
12
+ * `useSQLiteContext`. Renders nothing while opening or on failure with no `onError`; on failure
13
+ * with `onError`, calls it and renders nothing. Closes the database before re-opening and on
14
+ * unmount.
15
+ */
16
+ export declare const SQLiteProvider: import("@vue/runtime-core").DefineSetupFnComponent<ISQLiteProviderProps, {}, {}, ISQLiteProviderProps & {}, import("@vue/runtime-core").PublicProps>;
17
+ /**
18
+ * Reads the `SQLiteDatabase` opened by the nearest ancestor `<SQLiteProvider>`. Throws when
19
+ * called outside one.
20
+ */
21
+ export declare function useSQLiteContext(): SQLiteDatabase;
@@ -0,0 +1,69 @@
1
+ // Vue twin of upstream's `SQLiteProvider`/`useSQLiteContext`
2
+ // (.vendors/expo @ origin/sdk-57, packages/expo-sqlite/src/hooks.tsx). React's mechanics
3
+ // (useEffect/React.use/Suspense) don't transfer; this reproduces the OBSERVABLE contract with
4
+ // Vue's own provide/inject, following packages/navigation/src/vue/navigation-context.ts's shape
5
+ // (a symbol-keyed InjectionKey, a `require*` getter that throws with a hook-scoped message).
6
+ //
7
+ // Deliberately excluded, mirroring core's own `IOpenDatabaseOptions` (see core/types.ts):
8
+ // `assetSource` — needs `expo-asset`, out of scope for this package.
9
+ // Deliberately excluded, this pass only: Suspense integration (`useSuspense`). Vue has its own
10
+ // `<Suspense>` + async `setup()` idiom instead of React's `use()`; wiring this Provider into it is
11
+ // a separate, later decision, not a straight port of React's `useSuspense` flag.
12
+ import { defineComponent, inject, onUnmounted, provide, shallowRef, watch, } from '@vue/runtime-core';
13
+ import { openDatabaseAsync } from '../core/index.js';
14
+ const SQLITE_CONTEXT_KEY = Symbol('sqlite-context');
15
+ function toError(reason) {
16
+ return reason instanceof Error ? reason : new Error(String(reason));
17
+ }
18
+ /**
19
+ * Opens `databaseName` (re-opening whenever `databaseName`/`directory`/`options`/`onInit`
20
+ * change) and provides the resulting `SQLiteDatabase` to its default-slot children via
21
+ * `useSQLiteContext`. Renders nothing while opening or on failure with no `onError`; on failure
22
+ * with `onError`, calls it and renders nothing. Closes the database before re-opening and on
23
+ * unmount.
24
+ */
25
+ export const SQLiteProvider = defineComponent((props, { slots }) => {
26
+ const database = shallowRef(null);
27
+ provide(SQLITE_CONTEXT_KEY, database);
28
+ // Async watch callback: Vue's `callWithAsyncErrorHandling` attaches a `.catch` to the
29
+ // returned promise and routes a rejection through `app.config.errorHandler`
30
+ // (`handleError`) — the same channel `mount()` wires to the engine's shared reporter (see
31
+ // packages/navigation's composables.test.ts). So a thrown `Error` here IS the Vue-idiomatic
32
+ // "rethrow", not a swallowed unhandled rejection.
33
+ watch(() => [props.databaseName, props.directory, props.options, props.onInit], async () => {
34
+ const previous = database.value;
35
+ database.value = null;
36
+ await previous?.closeAsync();
37
+ const { databaseName, directory, options, onInit, onError } = props;
38
+ try {
39
+ database.value = await openDatabaseAsync(databaseName, { ...options, onInit }, directory);
40
+ }
41
+ catch (reason) {
42
+ const error = toError(reason);
43
+ if (onError !== undefined) {
44
+ onError(error);
45
+ }
46
+ else {
47
+ throw error;
48
+ }
49
+ }
50
+ }, { immediate: true });
51
+ onUnmounted(() => {
52
+ void database.value?.closeAsync();
53
+ });
54
+ return () => (database.value !== null ? slots.default?.() : null);
55
+ }, {
56
+ name: 'SQLiteProvider',
57
+ props: ['databaseName', 'directory', 'options', 'onInit', 'onError'],
58
+ });
59
+ /**
60
+ * Reads the `SQLiteDatabase` opened by the nearest ancestor `<SQLiteProvider>`. Throws when
61
+ * called outside one.
62
+ */
63
+ export function useSQLiteContext() {
64
+ const context = inject(SQLITE_CONTEXT_KEY, undefined);
65
+ if (context === undefined || context.value === null) {
66
+ throw new Error('useSQLiteContext must be used within a <SQLiteProvider>');
67
+ }
68
+ return context.value;
69
+ }
@@ -0,0 +1,2 @@
1
+ export * from '../core';
2
+ export * from './sqlite.service';
@@ -0,0 +1,3 @@
1
+ export * from '../core';
2
+ export * from './sqlite.service';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/angular/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,44 @@
1
+ import { InjectionToken, type OnDestroy, type Provider } from '@angular/core';
2
+ import type { IOpenDatabaseOptions } from '../core';
3
+ import * as i0 from "@angular/core";
4
+ export interface ISqliteConfig {
5
+ /** The name of the database file to open. */
6
+ databaseName: string;
7
+ /** The directory the database file is located in. Defaults to `defaultDatabaseDirectory`. */
8
+ directory?: string;
9
+ /** Open options — `onInit` runs once, right after the native handle opens. */
10
+ options?: IOpenDatabaseOptions;
11
+ /**
12
+ * Called instead of the failure sitting quietly in `SqliteService#error` — mirrors upstream's
13
+ * `SQLiteProviderProps.onError`. Omit it to read the failure off `error()` instead.
14
+ */
15
+ onError?: (error: Error) => void;
16
+ }
17
+ export declare const SQLITE_CONFIG: InjectionToken<ISqliteConfig>;
18
+ /**
19
+ * Declarative config for `SqliteService`'s app-wide database — pass to `bootstrapApplication`'s
20
+ * (or any environment injector's) `providers`, mirroring mounting `<SQLiteProvider>` once near
21
+ * the app root.
22
+ */
23
+ export declare function provideSqliteDatabase(config: ISqliteConfig): Provider;
24
+ export declare class SqliteService implements OnDestroy {
25
+ private readonly config;
26
+ private readonly onErrorHandler;
27
+ private readonly dbResource;
28
+ /**
29
+ * The resolved database, or `undefined` before `open()` has resolved. `resource()`'s own
30
+ * contract: reading this while `error()` is set RE-THROWS that error instead of returning —
31
+ * this IS the "propagates" half of upstream's `onError` contract for a caller that reads it
32
+ * directly (e.g. from a template's `@if (sqlite.database(); as db)`).
33
+ */
34
+ readonly database: import("@angular/core").WritableSignal<import(".").SQLiteDatabase | undefined>;
35
+ /** The open failure, if any — reading `error()` itself never throws, only `database()` does. */
36
+ readonly error: import("@angular/core").Signal<Error | undefined>;
37
+ readonly isLoading: import("@angular/core").Signal<boolean>;
38
+ constructor();
39
+ /** Opens (or re-opens, for a new config) the app-wide database. */
40
+ open(config: ISqliteConfig): void;
41
+ ngOnDestroy(): void;
42
+ static ɵfac: i0.ɵɵFactoryDeclaration<SqliteService, never>;
43
+ static ɵprov: i0.ɵɵInjectableDeclaration<SqliteService>;
44
+ }
@@ -0,0 +1,85 @@
1
+ // Angular's DI twin of upstream's `<SQLiteProvider>`/`useSQLiteContext`
2
+ // (.vendors/expo@sdk-57 packages/expo-sqlite/src/hooks.tsx): ONE database instance app-wide by
3
+ // default, opened once and read through DI instead of a React context.
4
+ //
5
+ // Declarative config goes through `provideSqliteDatabase()` — the
6
+ // `providers: [{ provide: TOKEN, useValue }]` pattern this repo already uses for
7
+ // gate-demand.ts's `provideGateDemand()` — rather than a scoping directive like navigation's
8
+ // `symbioteNavigationScope`. That directive pattern deliberately mints a FRESH service instance
9
+ // per usage (one per route); wrong here, since a database is a singleton to open once, not
10
+ // something to re-scope per screen.
11
+ //
12
+ // Async state rides Angular's own `resource()` (adapters/angular/src/render/index.ts already
13
+ // leans on it for TransferState) rather than a hand-rolled Promise/Observable — it is the
14
+ // signals-first primitive this Angular adapter already uses for "async value + error + loading",
15
+ // so `database`/`error`/`isLoading` come straight off it instead of a second, parallel state
16
+ // machine. Its own contract already matches upstream's non-Suspense provider: a failure PARKS in
17
+ // `error()` rather than throwing, exactly like `SQLiteProviderNonSuspense`'s `onError` branch
18
+ // parks it in React state instead of re-throwing.
19
+ //
20
+ // Deliberately excluded, same as `../core`: `assetSource` (needs `expo-asset`, out of scope).
21
+ // No Suspense equivalent — Angular has none.
22
+ import { Injectable, InjectionToken, effect, inject, resource, signal, } from '@angular/core';
23
+ import { openDatabaseAsync } from '../core';
24
+ import * as i0 from "@angular/core";
25
+ export const SQLITE_CONFIG = new InjectionToken('symbiote.sqlite-config');
26
+ /**
27
+ * Declarative config for `SqliteService`'s app-wide database — pass to `bootstrapApplication`'s
28
+ * (or any environment injector's) `providers`, mirroring mounting `<SQLiteProvider>` once near
29
+ * the app root.
30
+ */
31
+ export function provideSqliteDatabase(config) {
32
+ return { provide: SQLITE_CONFIG, useValue: config };
33
+ }
34
+ export class SqliteService {
35
+ config = signal(undefined, /* @ts-ignore */
36
+ ...(ngDevMode ? [{ debugName: "config" }] : /* istanbul ignore next */ []));
37
+ onErrorHandler = signal(undefined, /* @ts-ignore */
38
+ ...(ngDevMode ? [{ debugName: "onErrorHandler" }] : /* istanbul ignore next */ []));
39
+ dbResource = resource({ ...(ngDevMode ? { debugName: "dbResource" } : /* istanbul ignore next */ {}), params: () => this.config(),
40
+ loader: ({ params }) => openDatabaseAsync(params.databaseName, params.options, params.directory) });
41
+ /**
42
+ * The resolved database, or `undefined` before `open()` has resolved. `resource()`'s own
43
+ * contract: reading this while `error()` is set RE-THROWS that error instead of returning —
44
+ * this IS the "propagates" half of upstream's `onError` contract for a caller that reads it
45
+ * directly (e.g. from a template's `@if (sqlite.database(); as db)`).
46
+ */
47
+ database = this.dbResource.value;
48
+ /** The open failure, if any — reading `error()` itself never throws, only `database()` does. */
49
+ error = this.dbResource.error;
50
+ isLoading = this.dbResource.isLoading;
51
+ constructor() {
52
+ const injected = inject(SQLITE_CONFIG, { optional: true });
53
+ if (injected)
54
+ this.open(injected);
55
+ effect(() => {
56
+ const raw = this.dbResource.error();
57
+ if (raw === undefined)
58
+ return;
59
+ const error = raw instanceof Error ? raw : new Error(String(raw));
60
+ this.onErrorHandler()?.(error);
61
+ });
62
+ }
63
+ /** Opens (or re-opens, for a new config) the app-wide database. */
64
+ open(config) {
65
+ this.onErrorHandler.set(config.onError);
66
+ this.config.set(config);
67
+ }
68
+ // ponytail: closes only the CURRENTLY resolved handle, on the service's own teardown
69
+ // (providedIn: 'root' → root injector destruction). Re-opening with a different config does
70
+ // not close the previous handle first, unlike upstream's `getDatabaseAsync` memo — add that if
71
+ // an app actually calls `open()` more than once per lifetime.
72
+ ngOnDestroy() {
73
+ // `hasValue()` never throws, unlike reading `.value()` directly on an errored resource.
74
+ if (!this.dbResource.hasValue())
75
+ return;
76
+ void this.dbResource.value().closeAsync();
77
+ }
78
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SqliteService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
79
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SqliteService, providedIn: 'root' });
80
+ }
81
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: SqliteService, decorators: [{
82
+ type: Injectable,
83
+ args: [{ providedIn: 'root' }]
84
+ }], ctorParameters: () => [] });
85
+ //# sourceMappingURL=sqlite.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite.service.js","sourceRoot":"","sources":["../../src/angular/sqlite.service.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,+FAA+F;AAC/F,uEAAuE;AACvE,EAAE;AACF,kEAAkE;AAClE,iFAAiF;AACjF,6FAA6F;AAC7F,gGAAgG;AAChG,2FAA2F;AAC3F,oCAAoC;AACpC,EAAE;AACF,6FAA6F;AAC7F,0FAA0F;AAC1F,iGAAiG;AACjG,6FAA6F;AAC7F,iGAAiG;AACjG,8FAA8F;AAC9F,kDAAkD;AAClD,EAAE;AACF,8FAA8F;AAC9F,6CAA6C;AAE7C,OAAO,EACL,UAAU,EACV,cAAc,EACd,MAAM,EACN,MAAM,EACN,QAAQ,EACR,MAAM,GAGP,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;;AAiB5C,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,cAAc,CAC7C,wBAAwB,CACzB,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAqB;IACzD,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AACtD,CAAC;AAGD,MAAM,OAAO,aAAa;IACP,MAAM,GAAG,MAAM,CAA4B,SAAS;+EAAC,CAAC;IACtD,cAAc,GAAG,MAAM,CAEtC,SAAS;uFAAC,CAAC;IAEI,UAAU,GAAG,QAAQ,iFACpC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE;QAC3B,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CACrB,iBAAiB,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,GAC1E,CAAC;IAEH;;;;;OAKG;IACM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;IAC1C,gGAAgG;IACvF,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;IAC9B,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;IAE/C;QACE,MAAM,QAAQ,GAAG,MAAM,CAAC,aAAa,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3D,IAAI,QAAQ;YAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAElC,MAAM,CAAC,GAAG,EAAE;YACV,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YACpC,IAAI,GAAG,KAAK,SAAS;gBAAE,OAAO;YAC9B,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAClE,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,mEAAmE;IACnE,IAAI,CAAC,MAAqB;QACxB,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACxC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1B,CAAC;IAED,qFAAqF;IACrF,4FAA4F;IAC5F,+FAA+F;IAC/F,8DAA8D;IAC9D,WAAW;QACT,wFAAwF;QACxF,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE;YAAE,OAAO;QACxC,KAAK,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,CAAC;IAC5C,CAAC;uGAjDU,aAAa;2GAAb,aAAa,cADA,MAAM;;2FACnB,aAAa;kBADzB,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE"}
@@ -0,0 +1,10 @@
1
+ export { SQLiteDatabase, defaultDatabaseDirectory, bundledExtensions, openDatabaseAsync, openDatabaseSync, deserializeDatabaseAsync, deserializeDatabaseSync, deleteDatabaseAsync, deleteDatabaseSync, backupDatabaseAsync, backupDatabaseSync, addDatabaseChangeListener, } from './sqlite-database';
2
+ export type { ISQLiteOpenOptions, IDatabaseChangeEvent, IOnInitCallback, IOpenDatabaseOptions, } from './sqlite-database';
3
+ export { SQLiteStatement } from './sqlite-statement';
4
+ export type { ISQLiteBindParams, ISQLiteBindValue, ISQLiteExecuteAsyncResult, ISQLiteExecuteSyncResult, ISQLiteRunResult, ISQLiteVariadicBindParams, } from './sqlite-statement';
5
+ export { SQLiteSession } from './sqlite-session';
6
+ export type { IChangeset } from './sqlite-session';
7
+ export { SQLiteTaggedQuery } from './sqlite-tagged-query';
8
+ export { parseSQLQuery } from './query-utils';
9
+ export type { ISQLParsedInfo } from './query-utils';
10
+ export { createDatabasePath, basename } from './path-utils';
@@ -0,0 +1,7 @@
1
+ export { SQLiteDatabase, defaultDatabaseDirectory, bundledExtensions, openDatabaseAsync, openDatabaseSync, deserializeDatabaseAsync, deserializeDatabaseSync, deleteDatabaseAsync, deleteDatabaseSync, backupDatabaseAsync, backupDatabaseSync, addDatabaseChangeListener, } from './sqlite-database';
2
+ export { SQLiteStatement } from './sqlite-statement';
3
+ export { SQLiteSession } from './sqlite-session';
4
+ export { SQLiteTaggedQuery } from './sqlite-tagged-query';
5
+ export { parseSQLQuery } from './query-utils';
6
+ export { createDatabasePath, basename } from './path-utils';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,wBAAwB,EACxB,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAQ3B,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAUrD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG9C,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,65 @@
1
+ import type { NativeSession } from './native-session';
2
+ import type { NativeStatement } from './native-statement';
3
+ /** An instance of the native SQLite database handle. */
4
+ export declare class NativeDatabase {
5
+ constructor(databasePath: string, options?: ISQLiteOpenOptions, serializedData?: Uint8Array);
6
+ initAsync(): Promise<void>;
7
+ isInTransactionAsync(): Promise<boolean>;
8
+ closeAsync(): Promise<void>;
9
+ execAsync(source: string): Promise<void>;
10
+ serializeAsync(databaseName: string): Promise<Uint8Array>;
11
+ prepareAsync(nativeStatement: NativeStatement, source: string): Promise<NativeStatement>;
12
+ createSessionAsync(nativeSession: NativeSession, dbName: string): Promise<NativeSession>;
13
+ loadExtensionAsync(libPath: string, entryPoint?: string): Promise<void>;
14
+ initSync(): void;
15
+ isInTransactionSync(): boolean;
16
+ closeSync(): void;
17
+ execSync(source: string): void;
18
+ serializeSync(databaseName: string): Uint8Array;
19
+ prepareSync(nativeStatement: NativeStatement, source: string): NativeStatement;
20
+ createSessionSync(nativeSession: NativeSession, dbName: string): NativeSession;
21
+ loadExtensionSync(libPath: string, entryPoint?: string): void;
22
+ /** Only available when the native module was built against a libSQL-backed SQLite. */
23
+ syncLibSQL(): Promise<void>;
24
+ }
25
+ /** Options for opening a database. */
26
+ export type ISQLiteOpenOptions = {
27
+ /**
28
+ * Whether to call the [`sqlite3_update_hook()`](https://www.sqlite.org/c3ref/update_hook.html)
29
+ * function and enable `onDatabaseChange` events.
30
+ * @default false
31
+ */
32
+ enableChangeListener?: boolean;
33
+ /**
34
+ * Whether to create a new connection even if a connection with the same database name exists
35
+ * in cache.
36
+ * @default false
37
+ */
38
+ useNewConnection?: boolean;
39
+ /**
40
+ * Finalize unclosed statements automatically when the database is closed.
41
+ * @default true
42
+ * @hidden
43
+ */
44
+ finalizeUnusedStatementsBeforeClosing?: boolean;
45
+ /** Options for libSQL integration. */
46
+ libSQLOptions?: {
47
+ /** The URL of the libSQL server. */
48
+ url: string;
49
+ /** The auth token for the libSQL server. */
50
+ authToken: string;
51
+ /**
52
+ * Whether to use remote-only without syncing to a local database.
53
+ * @default false
54
+ */
55
+ remoteOnly?: boolean;
56
+ };
57
+ };
58
+ type IFlattenedOpenOptions = Omit<ISQLiteOpenOptions, 'libSQLOptions'> & {
59
+ libSQLUrl?: string;
60
+ libSQLAuthToken?: string;
61
+ libSQLRemoteOnly?: boolean;
62
+ };
63
+ /** Flattens `ISQLiteOpenOptions` into the shape the native module expects. */
64
+ export declare function flattenOpenOptions(options: ISQLiteOpenOptions): IFlattenedOpenOptions;
65
+ export {};