silosdk 0.0.9 → 0.0.10

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 (52) hide show
  1. package/README.md +16 -5
  2. package/dist/internal/indexed-db.cjs +44 -0
  3. package/dist/internal/indexed-db.mjs +41 -0
  4. package/dist/media/shared.cjs +99 -0
  5. package/dist/media/shared.d.cts +26 -0
  6. package/dist/media/shared.d.mts +26 -0
  7. package/dist/media/shared.mjs +93 -0
  8. package/dist/media/storage.native.cjs +102 -0
  9. package/dist/media/storage.native.mjs +101 -0
  10. package/dist/media/storage.web.cjs +79 -0
  11. package/dist/media/storage.web.mjs +78 -0
  12. package/dist/media.cjs +5 -163
  13. package/dist/media.d.cts +7 -27
  14. package/dist/media.d.mts +7 -27
  15. package/dist/media.mjs +4 -161
  16. package/dist/media.web.cjs +9 -0
  17. package/dist/media.web.d.cts +12 -0
  18. package/dist/media.web.d.mts +12 -0
  19. package/dist/media.web.mjs +8 -0
  20. package/dist/settings/shared.cjs +63 -0
  21. package/dist/settings/shared.d.cts +19 -0
  22. package/dist/settings/shared.d.mts +19 -0
  23. package/dist/settings/shared.mjs +59 -0
  24. package/dist/settings/storage.native.cjs +24 -0
  25. package/dist/settings/storage.native.mjs +22 -0
  26. package/dist/settings/storage.web.cjs +34 -0
  27. package/dist/settings/storage.web.mjs +34 -0
  28. package/dist/settings.cjs +4 -66
  29. package/dist/settings.d.cts +4 -18
  30. package/dist/settings.d.mts +4 -18
  31. package/dist/settings.mjs +4 -64
  32. package/dist/settings.web.cjs +8 -0
  33. package/dist/settings.web.d.cts +6 -0
  34. package/dist/settings.web.d.mts +6 -0
  35. package/dist/settings.web.mjs +8 -0
  36. package/dist/store/shared.cjs +338 -0
  37. package/dist/store/shared.d.cts +58 -0
  38. package/dist/store/shared.d.mts +58 -0
  39. package/dist/store/shared.mjs +333 -0
  40. package/dist/store/storage.native.cjs +133 -0
  41. package/dist/store/storage.native.mjs +132 -0
  42. package/dist/store/storage.web.cjs +142 -0
  43. package/dist/store/storage.web.mjs +142 -0
  44. package/dist/store.cjs +4 -421
  45. package/dist/store.d.cts +4 -58
  46. package/dist/store.d.mts +4 -58
  47. package/dist/store.mjs +4 -421
  48. package/dist/store.web.cjs +15 -0
  49. package/dist/store.web.d.cts +7 -0
  50. package/dist/store.web.d.mts +7 -0
  51. package/dist/store.web.mjs +12 -0
  52. package/package.json +31 -1
@@ -0,0 +1,78 @@
1
+ import { createIndexedDbOpener, requestResult, transactionDone } from "../internal/indexed-db.mjs";
2
+ import { createMediaRef, extensionForMimeType } from "./shared.mjs";
3
+ import { randomUUID } from "expo-crypto";
4
+
5
+ //#region src/media/storage.web.ts
6
+ const objectUrls = /* @__PURE__ */ new Map();
7
+ const mediaStorage = {
8
+ importMedia,
9
+ resolveMediaUri,
10
+ deleteMedia
11
+ };
12
+ const openSiloMediaIndexedDb = createIndexedDbOpener("silo-media", 1, (db) => {
13
+ if (!db.objectStoreNames.contains("media_files")) db.createObjectStore("media_files", { keyPath: "ref" });
14
+ if (!db.objectStoreNames.contains("media_blobs")) db.createObjectStore("media_blobs", { keyPath: "ref" });
15
+ });
16
+ async function importMedia(input) {
17
+ const id = randomUUID();
18
+ const ref = createMediaRef(input.kind, id);
19
+ const blob = await (await fetch(input.uri)).blob();
20
+ const name = input.name ?? `${id}${extensionForMimeType(input.mimeType ?? blob.type)}`;
21
+ const mimeType = input.mimeType ?? (blob.type || null);
22
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
23
+ const transaction = (await openSiloMediaIndexedDb()).transaction(["media_files", "media_blobs"], "readwrite");
24
+ transaction.objectStore("media_files").put({
25
+ ref,
26
+ uri: ref,
27
+ kind: input.kind,
28
+ name,
29
+ mimeType,
30
+ size: blob.size,
31
+ createdAt: timestamp,
32
+ data: JSON.stringify(input.data ?? {})
33
+ });
34
+ transaction.objectStore("media_blobs").put({
35
+ ref,
36
+ blob
37
+ });
38
+ await transactionDone(transaction);
39
+ const uri = URL.createObjectURL(blob);
40
+ objectUrls.set(ref, uri);
41
+ return {
42
+ ref,
43
+ uri
44
+ };
45
+ }
46
+ async function resolveMediaUri(ref) {
47
+ const existingUrl = objectUrls.get(ref);
48
+ if (existingUrl) return existingUrl;
49
+ const transaction = (await openSiloMediaIndexedDb()).transaction("media_blobs", "readonly");
50
+ const done = transactionDone(transaction);
51
+ const row = await requestResult(transaction.objectStore("media_blobs").get(ref));
52
+ await done;
53
+ if (!row) return null;
54
+ const uri = URL.createObjectURL(row.blob);
55
+ objectUrls.set(ref, uri);
56
+ return uri;
57
+ }
58
+ async function deleteMedia(ref) {
59
+ const db = await openSiloMediaIndexedDb();
60
+ const readTransaction = db.transaction("media_files", "readonly");
61
+ const readDone = transactionDone(readTransaction);
62
+ const existing = await requestResult(readTransaction.objectStore("media_files").get(ref));
63
+ await readDone;
64
+ if (!existing) return false;
65
+ const transaction = db.transaction(["media_files", "media_blobs"], "readwrite");
66
+ transaction.objectStore("media_files").delete(ref);
67
+ transaction.objectStore("media_blobs").delete(ref);
68
+ await transactionDone(transaction);
69
+ const objectUrl = objectUrls.get(ref);
70
+ if (objectUrl) {
71
+ URL.revokeObjectURL(objectUrl);
72
+ objectUrls.delete(ref);
73
+ }
74
+ return true;
75
+ }
76
+
77
+ //#endregion
78
+ export { mediaStorage };
package/dist/media.cjs CHANGED
@@ -1,167 +1,9 @@
1
- const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
2
- let expo_crypto = require("expo-crypto");
3
- let expo_sqlite = require("expo-sqlite");
4
- let __tanstack_react_query = require("@tanstack/react-query");
5
- let expo_file_system = require("expo-file-system");
1
+ const require_shared = require('./media/shared.cjs');
2
+ const require_storage_native = require('./media/storage.native.cjs');
6
3
 
7
- //#region src/media/index.ts
8
- const media = {
9
- queryOptions(ref) {
10
- return (0, __tanstack_react_query.queryOptions)({
11
- queryKey: mediaQueryKey(ref),
12
- queryFn: () => resolveMediaUri(ref)
13
- });
14
- },
15
- mutationOptions(options = {}) {
16
- return (0, __tanstack_react_query.mutationOptions)({
17
- mutationKey: [
18
- "silo",
19
- "media",
20
- "import"
21
- ],
22
- mutationFn: async (input) => {
23
- const imported = await importMedia(input);
24
- options.queryClient?.setQueryData(mediaQueryKey(imported.ref), imported.uri);
25
- return imported.ref;
26
- }
27
- });
28
- },
29
- delete(ref) {
30
- return deleteMedia(ref);
31
- },
32
- deleteMutationOptions(options = {}) {
33
- return (0, __tanstack_react_query.mutationOptions)({
34
- mutationKey: [
35
- "silo",
36
- "media",
37
- "delete"
38
- ],
39
- mutationFn: async (ref) => {
40
- const deleted = await deleteMedia(ref);
41
- if (isMediaRef(ref)) options.queryClient?.setQueryData(mediaQueryKey(ref), null);
42
- return deleted;
43
- }
44
- });
45
- }
46
- };
47
- function isMediaRef(value) {
48
- return typeof value === "string" && value.startsWith("media://");
49
- }
50
- function mediaQueryKey(ref) {
51
- return [
52
- "silo",
53
- "media",
54
- ref ?? null
55
- ];
56
- }
57
- async function importMedia(input) {
58
- assertMediaKind(input.kind);
59
- const id = (0, expo_crypto.randomUUID)();
60
- const ref = createMediaRef(input.kind, id);
61
- const source = new expo_file_system.File(input.uri);
62
- const name = input.name ?? source.name ?? `${id}${source.extension}`;
63
- const destinationDirectory = mediaDirectory(input.kind);
64
- destinationDirectory.create({
65
- idempotent: true,
66
- intermediates: true
67
- });
68
- const destination = new expo_file_system.File(destinationDirectory, `${id}${extensionFor(name)}`);
69
- await source.copy(destination);
70
- const info = destination.info();
71
- const mimeType = input.mimeType ?? (destination.type || null);
72
- const size = info.size ?? destination.size;
73
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
74
- insertMediaFile({
75
- ref,
76
- uri: destination.uri,
77
- kind: input.kind,
78
- name,
79
- mimeType,
80
- size,
81
- createdAt: timestamp,
82
- data: input.data ?? {}
83
- });
84
- return {
85
- ref,
86
- uri: destination.uri
87
- };
88
- }
89
- function resolveMediaUri(ref) {
90
- if (!isMediaRef(ref)) return null;
91
- const row = getMediaFile(ref);
92
- if (!row) return null;
93
- return new expo_file_system.File(row.uri).exists ? row.uri : null;
94
- }
95
- async function deleteMedia(ref) {
96
- if (!isMediaRef(ref)) return false;
97
- const row = getMediaFile(ref);
98
- if (!row) return false;
99
- const file = new expo_file_system.File(row.uri);
100
- if (file.exists) await file.delete();
101
- deleteMediaFileRow(ref);
102
- return true;
103
- }
104
- function getMediaFile(ref) {
105
- return getDatabase().getFirstSync(`SELECT ref, uri FROM media_files WHERE ref = ?`, [ref]);
106
- }
107
- function createMediaRef(kind, id) {
108
- return `media://silo/${kindDirectoryName(kind)}/${id}`;
109
- }
110
- function mediaDirectory(kind) {
111
- return new expo_file_system.Directory(expo_file_system.Paths.document, "silo", "media", kindDirectoryName(kind));
112
- }
113
- function kindDirectoryName(kind) {
114
- switch (kind) {
115
- case "image": return "images";
116
- case "video": return "videos";
117
- case "audio": return "audio";
118
- case "file": return "files";
119
- }
120
- }
121
- function extensionFor(name) {
122
- return name.match(/\.[A-Za-z0-9]+$/)?.[0] ?? "";
123
- }
124
- function assertMediaKind(kind) {
125
- if (kind !== "image" && kind !== "video" && kind !== "audio" && kind !== "file") throw new Error("Media kind must be one of \"image\", \"video\", \"audio\", or \"file\".");
126
- }
127
- let database;
128
- function getDatabase() {
129
- if (!database) {
130
- database = (0, expo_sqlite.openDatabaseSync)("silo.db");
131
- database.execSync(`
132
- PRAGMA journal_mode = WAL;
133
-
134
- CREATE TABLE IF NOT EXISTS media_files (
135
- ref TEXT PRIMARY KEY,
136
- uri TEXT NOT NULL,
137
- kind TEXT NOT NULL,
138
- name TEXT NOT NULL,
139
- mimeType TEXT,
140
- size INTEGER NOT NULL,
141
- createdAt TEXT NOT NULL,
142
- data TEXT NOT NULL
143
- );
144
- `);
145
- }
146
- return database;
147
- }
148
- function insertMediaFile(file) {
149
- getDatabase().runSync(`INSERT INTO media_files (ref, uri, kind, name, mimeType, size, createdAt, data)
150
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
151
- file.ref,
152
- file.uri,
153
- file.kind,
154
- file.name,
155
- file.mimeType,
156
- file.size,
157
- file.createdAt,
158
- JSON.stringify(file.data)
159
- ]);
160
- }
161
- function deleteMediaFileRow(ref) {
162
- getDatabase().runSync(`DELETE FROM media_files WHERE ref = ?`, [ref]);
163
- }
4
+ //#region src/media/index.native.ts
5
+ const media = require_shared.createMediaApi(require_storage_native.mediaStorage);
164
6
 
165
7
  //#endregion
166
- exports.isMediaRef = isMediaRef;
8
+ exports.isMediaRef = require_shared.isMediaRef;
167
9
  exports.media = media;
package/dist/media.d.cts CHANGED
@@ -1,32 +1,12 @@
1
- import { QueryClient, UseMutationOptions, UseQueryOptions } from "@tanstack/react-query";
1
+ import { MediaData, MediaDeleteInput, MediaImportInput, MediaJson, MediaKind, MediaMutationOptions, MediaQueryKey, MediaRef, isMediaRef } from "./media/shared.cjs";
2
+ import * as _tanstack_react_query2 from "@tanstack/react-query";
2
3
 
3
- //#region src/media/index.d.ts
4
- type MediaRef = `media://${string}`;
5
- type MediaKind = 'image' | 'video' | 'audio' | 'file';
6
- type MediaJson = string | number | boolean | null | MediaJson[] | {
7
- [key: string]: MediaJson;
8
- };
9
- type MediaData = {
10
- [key: string]: MediaJson;
11
- };
12
- type MediaImportInput = {
13
- uri: string;
14
- kind: MediaKind;
15
- name?: string;
16
- mimeType?: string | null;
17
- data?: MediaData;
18
- };
19
- type MediaDeleteInput = MediaRef | string | null | undefined;
20
- type MediaQueryKey = readonly ['silo', 'media', MediaRef | string | null];
21
- type MediaMutationOptions = {
22
- queryClient?: QueryClient;
23
- };
4
+ //#region src/media/index.native.d.ts
24
5
  declare const media: {
25
- queryOptions(ref: MediaRef | string | null | undefined): UseQueryOptions<string | null, Error, string | null, MediaQueryKey>;
26
- mutationOptions(options?: MediaMutationOptions): UseMutationOptions<MediaRef, Error, MediaImportInput>;
6
+ queryOptions(ref: MediaRef | string | null | undefined): _tanstack_react_query2.UseQueryOptions<string | null, Error, string | null, MediaQueryKey>;
7
+ mutationOptions(options?: MediaMutationOptions): _tanstack_react_query2.UseMutationOptions<MediaRef, Error, MediaImportInput>;
27
8
  delete(ref: MediaDeleteInput): Promise<boolean>;
28
- deleteMutationOptions(options?: MediaMutationOptions): UseMutationOptions<boolean, Error, MediaDeleteInput>;
9
+ deleteMutationOptions(options?: MediaMutationOptions): _tanstack_react_query2.UseMutationOptions<boolean, Error, MediaDeleteInput>;
29
10
  };
30
- declare function isMediaRef(value: unknown): value is MediaRef;
31
11
  //#endregion
32
- export { MediaData, MediaDeleteInput, MediaImportInput, MediaJson, MediaKind, MediaMutationOptions, MediaQueryKey, MediaRef, isMediaRef, media };
12
+ export { type MediaData, type MediaDeleteInput, type MediaImportInput, type MediaJson, type MediaKind, type MediaMutationOptions, type MediaQueryKey, type MediaRef, isMediaRef, media };
package/dist/media.d.mts CHANGED
@@ -1,32 +1,12 @@
1
- import { QueryClient, UseMutationOptions, UseQueryOptions } from "@tanstack/react-query";
1
+ import { MediaData, MediaDeleteInput, MediaImportInput, MediaJson, MediaKind, MediaMutationOptions, MediaQueryKey, MediaRef, isMediaRef } from "./media/shared.mjs";
2
+ import * as _tanstack_react_query2 from "@tanstack/react-query";
2
3
 
3
- //#region src/media/index.d.ts
4
- type MediaRef = `media://${string}`;
5
- type MediaKind = 'image' | 'video' | 'audio' | 'file';
6
- type MediaJson = string | number | boolean | null | MediaJson[] | {
7
- [key: string]: MediaJson;
8
- };
9
- type MediaData = {
10
- [key: string]: MediaJson;
11
- };
12
- type MediaImportInput = {
13
- uri: string;
14
- kind: MediaKind;
15
- name?: string;
16
- mimeType?: string | null;
17
- data?: MediaData;
18
- };
19
- type MediaDeleteInput = MediaRef | string | null | undefined;
20
- type MediaQueryKey = readonly ['silo', 'media', MediaRef | string | null];
21
- type MediaMutationOptions = {
22
- queryClient?: QueryClient;
23
- };
4
+ //#region src/media/index.native.d.ts
24
5
  declare const media: {
25
- queryOptions(ref: MediaRef | string | null | undefined): UseQueryOptions<string | null, Error, string | null, MediaQueryKey>;
26
- mutationOptions(options?: MediaMutationOptions): UseMutationOptions<MediaRef, Error, MediaImportInput>;
6
+ queryOptions(ref: MediaRef | string | null | undefined): _tanstack_react_query2.UseQueryOptions<string | null, Error, string | null, MediaQueryKey>;
7
+ mutationOptions(options?: MediaMutationOptions): _tanstack_react_query2.UseMutationOptions<MediaRef, Error, MediaImportInput>;
27
8
  delete(ref: MediaDeleteInput): Promise<boolean>;
28
- deleteMutationOptions(options?: MediaMutationOptions): UseMutationOptions<boolean, Error, MediaDeleteInput>;
9
+ deleteMutationOptions(options?: MediaMutationOptions): _tanstack_react_query2.UseMutationOptions<boolean, Error, MediaDeleteInput>;
29
10
  };
30
- declare function isMediaRef(value: unknown): value is MediaRef;
31
11
  //#endregion
32
- export { MediaData, MediaDeleteInput, MediaImportInput, MediaJson, MediaKind, MediaMutationOptions, MediaQueryKey, MediaRef, isMediaRef, media };
12
+ export { type MediaData, type MediaDeleteInput, type MediaImportInput, type MediaJson, type MediaKind, type MediaMutationOptions, type MediaQueryKey, type MediaRef, isMediaRef, media };
package/dist/media.mjs CHANGED
@@ -1,165 +1,8 @@
1
- import { randomUUID } from "expo-crypto";
2
- import { openDatabaseSync } from "expo-sqlite";
3
- import { mutationOptions, queryOptions } from "@tanstack/react-query";
4
- import { Directory, File, Paths } from "expo-file-system";
1
+ import { createMediaApi, isMediaRef } from "./media/shared.mjs";
2
+ import { mediaStorage } from "./media/storage.native.mjs";
5
3
 
6
- //#region src/media/index.ts
7
- const media = {
8
- queryOptions(ref) {
9
- return queryOptions({
10
- queryKey: mediaQueryKey(ref),
11
- queryFn: () => resolveMediaUri(ref)
12
- });
13
- },
14
- mutationOptions(options = {}) {
15
- return mutationOptions({
16
- mutationKey: [
17
- "silo",
18
- "media",
19
- "import"
20
- ],
21
- mutationFn: async (input) => {
22
- const imported = await importMedia(input);
23
- options.queryClient?.setQueryData(mediaQueryKey(imported.ref), imported.uri);
24
- return imported.ref;
25
- }
26
- });
27
- },
28
- delete(ref) {
29
- return deleteMedia(ref);
30
- },
31
- deleteMutationOptions(options = {}) {
32
- return mutationOptions({
33
- mutationKey: [
34
- "silo",
35
- "media",
36
- "delete"
37
- ],
38
- mutationFn: async (ref) => {
39
- const deleted = await deleteMedia(ref);
40
- if (isMediaRef(ref)) options.queryClient?.setQueryData(mediaQueryKey(ref), null);
41
- return deleted;
42
- }
43
- });
44
- }
45
- };
46
- function isMediaRef(value) {
47
- return typeof value === "string" && value.startsWith("media://");
48
- }
49
- function mediaQueryKey(ref) {
50
- return [
51
- "silo",
52
- "media",
53
- ref ?? null
54
- ];
55
- }
56
- async function importMedia(input) {
57
- assertMediaKind(input.kind);
58
- const id = randomUUID();
59
- const ref = createMediaRef(input.kind, id);
60
- const source = new File(input.uri);
61
- const name = input.name ?? source.name ?? `${id}${source.extension}`;
62
- const destinationDirectory = mediaDirectory(input.kind);
63
- destinationDirectory.create({
64
- idempotent: true,
65
- intermediates: true
66
- });
67
- const destination = new File(destinationDirectory, `${id}${extensionFor(name)}`);
68
- await source.copy(destination);
69
- const info = destination.info();
70
- const mimeType = input.mimeType ?? (destination.type || null);
71
- const size = info.size ?? destination.size;
72
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
73
- insertMediaFile({
74
- ref,
75
- uri: destination.uri,
76
- kind: input.kind,
77
- name,
78
- mimeType,
79
- size,
80
- createdAt: timestamp,
81
- data: input.data ?? {}
82
- });
83
- return {
84
- ref,
85
- uri: destination.uri
86
- };
87
- }
88
- function resolveMediaUri(ref) {
89
- if (!isMediaRef(ref)) return null;
90
- const row = getMediaFile(ref);
91
- if (!row) return null;
92
- return new File(row.uri).exists ? row.uri : null;
93
- }
94
- async function deleteMedia(ref) {
95
- if (!isMediaRef(ref)) return false;
96
- const row = getMediaFile(ref);
97
- if (!row) return false;
98
- const file = new File(row.uri);
99
- if (file.exists) await file.delete();
100
- deleteMediaFileRow(ref);
101
- return true;
102
- }
103
- function getMediaFile(ref) {
104
- return getDatabase().getFirstSync(`SELECT ref, uri FROM media_files WHERE ref = ?`, [ref]);
105
- }
106
- function createMediaRef(kind, id) {
107
- return `media://silo/${kindDirectoryName(kind)}/${id}`;
108
- }
109
- function mediaDirectory(kind) {
110
- return new Directory(Paths.document, "silo", "media", kindDirectoryName(kind));
111
- }
112
- function kindDirectoryName(kind) {
113
- switch (kind) {
114
- case "image": return "images";
115
- case "video": return "videos";
116
- case "audio": return "audio";
117
- case "file": return "files";
118
- }
119
- }
120
- function extensionFor(name) {
121
- return name.match(/\.[A-Za-z0-9]+$/)?.[0] ?? "";
122
- }
123
- function assertMediaKind(kind) {
124
- if (kind !== "image" && kind !== "video" && kind !== "audio" && kind !== "file") throw new Error("Media kind must be one of \"image\", \"video\", \"audio\", or \"file\".");
125
- }
126
- let database;
127
- function getDatabase() {
128
- if (!database) {
129
- database = openDatabaseSync("silo.db");
130
- database.execSync(`
131
- PRAGMA journal_mode = WAL;
132
-
133
- CREATE TABLE IF NOT EXISTS media_files (
134
- ref TEXT PRIMARY KEY,
135
- uri TEXT NOT NULL,
136
- kind TEXT NOT NULL,
137
- name TEXT NOT NULL,
138
- mimeType TEXT,
139
- size INTEGER NOT NULL,
140
- createdAt TEXT NOT NULL,
141
- data TEXT NOT NULL
142
- );
143
- `);
144
- }
145
- return database;
146
- }
147
- function insertMediaFile(file) {
148
- getDatabase().runSync(`INSERT INTO media_files (ref, uri, kind, name, mimeType, size, createdAt, data)
149
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
150
- file.ref,
151
- file.uri,
152
- file.kind,
153
- file.name,
154
- file.mimeType,
155
- file.size,
156
- file.createdAt,
157
- JSON.stringify(file.data)
158
- ]);
159
- }
160
- function deleteMediaFileRow(ref) {
161
- getDatabase().runSync(`DELETE FROM media_files WHERE ref = ?`, [ref]);
162
- }
4
+ //#region src/media/index.native.ts
5
+ const media = createMediaApi(mediaStorage);
163
6
 
164
7
  //#endregion
165
8
  export { isMediaRef, media };
@@ -0,0 +1,9 @@
1
+ const require_shared = require('./media/shared.cjs');
2
+ const require_storage_web = require('./media/storage.web.cjs');
3
+
4
+ //#region src/media/index.web.ts
5
+ const media = require_shared.createMediaApi(require_storage_web.mediaStorage);
6
+
7
+ //#endregion
8
+ exports.isMediaRef = require_shared.isMediaRef;
9
+ exports.media = media;
@@ -0,0 +1,12 @@
1
+ import { MediaData, MediaDeleteInput, MediaImportInput, MediaJson, MediaKind, MediaMutationOptions, MediaQueryKey, MediaRef, isMediaRef } from "./media/shared.cjs";
2
+ import * as _tanstack_react_query0 from "@tanstack/react-query";
3
+
4
+ //#region src/media/index.web.d.ts
5
+ declare const media: {
6
+ queryOptions(ref: MediaRef | string | null | undefined): _tanstack_react_query0.UseQueryOptions<string | null, Error, string | null, MediaQueryKey>;
7
+ mutationOptions(options?: MediaMutationOptions): _tanstack_react_query0.UseMutationOptions<MediaRef, Error, MediaImportInput>;
8
+ delete(ref: MediaDeleteInput): Promise<boolean>;
9
+ deleteMutationOptions(options?: MediaMutationOptions): _tanstack_react_query0.UseMutationOptions<boolean, Error, MediaDeleteInput>;
10
+ };
11
+ //#endregion
12
+ export { type MediaData, type MediaDeleteInput, type MediaImportInput, type MediaJson, type MediaKind, type MediaMutationOptions, type MediaQueryKey, type MediaRef, isMediaRef, media };
@@ -0,0 +1,12 @@
1
+ import { MediaData, MediaDeleteInput, MediaImportInput, MediaJson, MediaKind, MediaMutationOptions, MediaQueryKey, MediaRef, isMediaRef } from "./media/shared.mjs";
2
+ import * as _tanstack_react_query0 from "@tanstack/react-query";
3
+
4
+ //#region src/media/index.web.d.ts
5
+ declare const media: {
6
+ queryOptions(ref: MediaRef | string | null | undefined): _tanstack_react_query0.UseQueryOptions<string | null, Error, string | null, MediaQueryKey>;
7
+ mutationOptions(options?: MediaMutationOptions): _tanstack_react_query0.UseMutationOptions<MediaRef, Error, MediaImportInput>;
8
+ delete(ref: MediaDeleteInput): Promise<boolean>;
9
+ deleteMutationOptions(options?: MediaMutationOptions): _tanstack_react_query0.UseMutationOptions<boolean, Error, MediaDeleteInput>;
10
+ };
11
+ //#endregion
12
+ export { type MediaData, type MediaDeleteInput, type MediaImportInput, type MediaJson, type MediaKind, type MediaMutationOptions, type MediaQueryKey, type MediaRef, isMediaRef, media };
@@ -0,0 +1,8 @@
1
+ import { createMediaApi, isMediaRef } from "./media/shared.mjs";
2
+ import { mediaStorage } from "./media/storage.web.mjs";
3
+
4
+ //#region src/media/index.web.ts
5
+ const media = createMediaApi(mediaStorage);
6
+
7
+ //#endregion
8
+ export { isMediaRef, media };
@@ -0,0 +1,63 @@
1
+ const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
+ let __tanstack_react_query = require("@tanstack/react-query");
3
+
4
+ //#region src/settings/shared.ts
5
+ const settingNames = /* @__PURE__ */ new Set();
6
+ const settingNamePattern = /^[A-Za-z][A-Za-z0-9_.:-]*$/;
7
+ function createSettingApi(storage) {
8
+ function setting(name, defaultValue) {
9
+ assertSettingName(name);
10
+ assertSettingValue(resolveDefault(defaultValue));
11
+ if (settingNames.has(name)) throw new Error(`Setting "${name}" is already registered. Define each setting once and import the existing setting instead.`);
12
+ settingNames.add(name);
13
+ const queryKey = [
14
+ "silo",
15
+ "setting",
16
+ name
17
+ ];
18
+ return {
19
+ name,
20
+ defaultValue,
21
+ queryKey,
22
+ queryOptions() {
23
+ return (0, __tanstack_react_query.queryOptions)({
24
+ queryKey,
25
+ queryFn: () => storage.read(name, defaultValue)
26
+ });
27
+ },
28
+ mutationOptions(options = {}) {
29
+ return (0, __tanstack_react_query.mutationOptions)({
30
+ mutationKey: queryKey,
31
+ mutationFn: async (valueOrUpdater) => {
32
+ const current = await storage.read(name, defaultValue);
33
+ const next = typeof valueOrUpdater === "function" ? valueOrUpdater(current) : valueOrUpdater;
34
+ await storage.write(name, next);
35
+ return next;
36
+ },
37
+ onSuccess(value) {
38
+ options.queryClient?.setQueryData(queryKey, value);
39
+ }
40
+ });
41
+ }
42
+ };
43
+ }
44
+ return { setting };
45
+ }
46
+ function storageKey(name) {
47
+ return `silo:setting:${name}`;
48
+ }
49
+ function resolveDefault(defaultValue) {
50
+ return typeof defaultValue === "function" ? defaultValue() : defaultValue;
51
+ }
52
+ function assertSettingValue(value) {
53
+ if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean" && value !== null) throw new Error("Settings must be strings, numbers, booleans, or null.");
54
+ }
55
+ function assertSettingName(name) {
56
+ if (!settingNamePattern.test(name)) throw new Error(`Setting names must start with a letter and contain only letters, numbers, underscores, dots, colons, or hyphens. Received "${name}".`);
57
+ }
58
+
59
+ //#endregion
60
+ exports.assertSettingValue = assertSettingValue;
61
+ exports.createSettingApi = createSettingApi;
62
+ exports.resolveDefault = resolveDefault;
63
+ exports.storageKey = storageKey;
@@ -0,0 +1,19 @@
1
+ import { QueryClient, UseMutationOptions, UseQueryOptions } from "@tanstack/react-query";
2
+
3
+ //#region src/settings/shared.d.ts
4
+ type SettingValue = string | number | boolean | null;
5
+ type SettingDefault<T extends SettingValue> = T | (() => T);
6
+ type SettingMutation<T extends SettingValue> = T | ((current: T) => T);
7
+ type SettingQueryKey = readonly ['silo', 'setting', string];
8
+ type SettingMutationOptions = {
9
+ queryClient?: QueryClient;
10
+ };
11
+ type Setting<T extends SettingValue> = {
12
+ readonly name: string;
13
+ readonly defaultValue: SettingDefault<T>;
14
+ readonly queryKey: SettingQueryKey;
15
+ queryOptions(): UseQueryOptions<T, Error, T, SettingQueryKey>;
16
+ mutationOptions(options?: SettingMutationOptions): UseMutationOptions<T, Error, SettingMutation<T>>;
17
+ };
18
+ //#endregion
19
+ export { Setting, SettingDefault, SettingMutation, SettingMutationOptions, SettingQueryKey, SettingValue };
@@ -0,0 +1,19 @@
1
+ import { QueryClient, UseMutationOptions, UseQueryOptions } from "@tanstack/react-query";
2
+
3
+ //#region src/settings/shared.d.ts
4
+ type SettingValue = string | number | boolean | null;
5
+ type SettingDefault<T extends SettingValue> = T | (() => T);
6
+ type SettingMutation<T extends SettingValue> = T | ((current: T) => T);
7
+ type SettingQueryKey = readonly ['silo', 'setting', string];
8
+ type SettingMutationOptions = {
9
+ queryClient?: QueryClient;
10
+ };
11
+ type Setting<T extends SettingValue> = {
12
+ readonly name: string;
13
+ readonly defaultValue: SettingDefault<T>;
14
+ readonly queryKey: SettingQueryKey;
15
+ queryOptions(): UseQueryOptions<T, Error, T, SettingQueryKey>;
16
+ mutationOptions(options?: SettingMutationOptions): UseMutationOptions<T, Error, SettingMutation<T>>;
17
+ };
18
+ //#endregion
19
+ export { Setting, SettingDefault, SettingMutation, SettingMutationOptions, SettingQueryKey, SettingValue };