@stardeck-customer-apps/data-store-sdk 0.3.2 → 0.4.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.
- package/dist/cli/generate-types.js +23 -12
- package/dist/cli/generate-types.mjs +23 -12
- package/dist/server/index.d.mts +13 -1
- package/dist/server/index.d.ts +13 -1
- package/dist/server/index.js +18 -3
- package/dist/server/index.mjs +18 -3
- package/package.json +1 -1
|
@@ -88,18 +88,29 @@ async function introspectSchemaSnapshot(executor) {
|
|
|
88
88
|
ORDER BY tc.table_name, tc.constraint_name, ku.ordinal_position`
|
|
89
89
|
),
|
|
90
90
|
executor.query(
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
91
|
+
// Read column pairings from pg_catalog: information_schema's
|
|
92
|
+
// constraint_column_usage is uncorrelated with key_column_usage, so
|
|
93
|
+
// joining them for a composite FK produces a cross product. Unnesting
|
|
94
|
+
// conkey/confkey together WITH ORDINALITY keeps referencing↔referenced
|
|
95
|
+
// columns paired and ordered.
|
|
96
|
+
`SELECT con.conname AS constraint_name,
|
|
97
|
+
rel.relname AS table_name,
|
|
98
|
+
att.attname AS column_name,
|
|
99
|
+
frel.relname AS referenced_table,
|
|
100
|
+
fatt.attname AS referenced_column,
|
|
101
|
+
CASE con.confdeltype WHEN 'a' THEN 'NO ACTION' WHEN 'r' THEN 'RESTRICT'
|
|
102
|
+
WHEN 'c' THEN 'CASCADE' WHEN 'n' THEN 'SET NULL' WHEN 'd' THEN 'SET DEFAULT' END AS delete_rule,
|
|
103
|
+
CASE con.confupdtype WHEN 'a' THEN 'NO ACTION' WHEN 'r' THEN 'RESTRICT'
|
|
104
|
+
WHEN 'c' THEN 'CASCADE' WHEN 'n' THEN 'SET NULL' WHEN 'd' THEN 'SET DEFAULT' END AS update_rule
|
|
105
|
+
FROM pg_constraint con
|
|
106
|
+
JOIN pg_class rel ON rel.oid = con.conrelid
|
|
107
|
+
JOIN pg_namespace ns ON ns.oid = rel.relnamespace
|
|
108
|
+
JOIN pg_class frel ON frel.oid = con.confrelid
|
|
109
|
+
JOIN LATERAL unnest(con.conkey, con.confkey) WITH ORDINALITY AS cols(conkey, confkey, ord) ON true
|
|
110
|
+
JOIN pg_attribute att ON att.attrelid = con.conrelid AND att.attnum = cols.conkey
|
|
111
|
+
JOIN pg_attribute fatt ON fatt.attrelid = con.confrelid AND fatt.attnum = cols.confkey
|
|
112
|
+
WHERE ns.nspname = 'public' AND con.contype = 'f'
|
|
113
|
+
ORDER BY rel.relname, con.conname, cols.ord`
|
|
103
114
|
),
|
|
104
115
|
executor.query(
|
|
105
116
|
`SELECT rel.relname AS table_name, con.conname AS name,
|
|
@@ -65,18 +65,29 @@ async function introspectSchemaSnapshot(executor) {
|
|
|
65
65
|
ORDER BY tc.table_name, tc.constraint_name, ku.ordinal_position`
|
|
66
66
|
),
|
|
67
67
|
executor.query(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
68
|
+
// Read column pairings from pg_catalog: information_schema's
|
|
69
|
+
// constraint_column_usage is uncorrelated with key_column_usage, so
|
|
70
|
+
// joining them for a composite FK produces a cross product. Unnesting
|
|
71
|
+
// conkey/confkey together WITH ORDINALITY keeps referencing↔referenced
|
|
72
|
+
// columns paired and ordered.
|
|
73
|
+
`SELECT con.conname AS constraint_name,
|
|
74
|
+
rel.relname AS table_name,
|
|
75
|
+
att.attname AS column_name,
|
|
76
|
+
frel.relname AS referenced_table,
|
|
77
|
+
fatt.attname AS referenced_column,
|
|
78
|
+
CASE con.confdeltype WHEN 'a' THEN 'NO ACTION' WHEN 'r' THEN 'RESTRICT'
|
|
79
|
+
WHEN 'c' THEN 'CASCADE' WHEN 'n' THEN 'SET NULL' WHEN 'd' THEN 'SET DEFAULT' END AS delete_rule,
|
|
80
|
+
CASE con.confupdtype WHEN 'a' THEN 'NO ACTION' WHEN 'r' THEN 'RESTRICT'
|
|
81
|
+
WHEN 'c' THEN 'CASCADE' WHEN 'n' THEN 'SET NULL' WHEN 'd' THEN 'SET DEFAULT' END AS update_rule
|
|
82
|
+
FROM pg_constraint con
|
|
83
|
+
JOIN pg_class rel ON rel.oid = con.conrelid
|
|
84
|
+
JOIN pg_namespace ns ON ns.oid = rel.relnamespace
|
|
85
|
+
JOIN pg_class frel ON frel.oid = con.confrelid
|
|
86
|
+
JOIN LATERAL unnest(con.conkey, con.confkey) WITH ORDINALITY AS cols(conkey, confkey, ord) ON true
|
|
87
|
+
JOIN pg_attribute att ON att.attrelid = con.conrelid AND att.attnum = cols.conkey
|
|
88
|
+
JOIN pg_attribute fatt ON fatt.attrelid = con.confrelid AND fatt.attnum = cols.confkey
|
|
89
|
+
WHERE ns.nspname = 'public' AND con.contype = 'f'
|
|
90
|
+
ORDER BY rel.relname, con.conname, cols.ord`
|
|
80
91
|
),
|
|
81
92
|
executor.query(
|
|
82
93
|
`SELECT rel.relname AS table_name, con.conname AS name,
|
package/dist/server/index.d.mts
CHANGED
|
@@ -140,7 +140,19 @@ interface DataStoreManifestEntry {
|
|
|
140
140
|
id: string;
|
|
141
141
|
name: string;
|
|
142
142
|
slug: string;
|
|
143
|
-
|
|
143
|
+
/**
|
|
144
|
+
* App-local handle for this project's connection. When present, the resolver
|
|
145
|
+
* matches it before the org-global slug/name.
|
|
146
|
+
*/
|
|
147
|
+
bindingKey?: string;
|
|
148
|
+
/**
|
|
149
|
+
* Store kind. `database` stores carry a `url`; `storage` stores do not (access
|
|
150
|
+
* is API-mediated by store id). Absent on manifests emitted before this field
|
|
151
|
+
* existed — treat absent as `database`.
|
|
152
|
+
*/
|
|
153
|
+
storeType?: "database" | "storage";
|
|
154
|
+
/** Connection string. Present for `database` stores only. */
|
|
155
|
+
url?: string;
|
|
144
156
|
accessLevel: "read" | "write" | "admin";
|
|
145
157
|
}
|
|
146
158
|
/**
|
package/dist/server/index.d.ts
CHANGED
|
@@ -140,7 +140,19 @@ interface DataStoreManifestEntry {
|
|
|
140
140
|
id: string;
|
|
141
141
|
name: string;
|
|
142
142
|
slug: string;
|
|
143
|
-
|
|
143
|
+
/**
|
|
144
|
+
* App-local handle for this project's connection. When present, the resolver
|
|
145
|
+
* matches it before the org-global slug/name.
|
|
146
|
+
*/
|
|
147
|
+
bindingKey?: string;
|
|
148
|
+
/**
|
|
149
|
+
* Store kind. `database` stores carry a `url`; `storage` stores do not (access
|
|
150
|
+
* is API-mediated by store id). Absent on manifests emitted before this field
|
|
151
|
+
* existed — treat absent as `database`.
|
|
152
|
+
*/
|
|
153
|
+
storeType?: "database" | "storage";
|
|
154
|
+
/** Connection string. Present for `database` stores only. */
|
|
155
|
+
url?: string;
|
|
144
156
|
accessLevel: "read" | "write" | "admin";
|
|
145
157
|
}
|
|
146
158
|
/**
|
package/dist/server/index.js
CHANGED
|
@@ -94,9 +94,14 @@ function readDataStoreManifest() {
|
|
|
94
94
|
try {
|
|
95
95
|
const parsed = JSON.parse(raw);
|
|
96
96
|
if (!Array.isArray(parsed)) return [];
|
|
97
|
-
return parsed.filter(
|
|
98
|
-
(
|
|
99
|
-
|
|
97
|
+
return parsed.filter((e) => {
|
|
98
|
+
if (typeof e !== "object" || e === null) return false;
|
|
99
|
+
const entry = e;
|
|
100
|
+
if (typeof entry.id !== "string" || typeof entry.name !== "string" || typeof entry.slug !== "string") {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
return entry.storeType === "storage" || typeof entry.url === "string";
|
|
104
|
+
});
|
|
100
105
|
} catch {
|
|
101
106
|
return [];
|
|
102
107
|
}
|
|
@@ -111,9 +116,13 @@ function resolveManifestEntry(entries, ref) {
|
|
|
111
116
|
}
|
|
112
117
|
if (ref.storeName) {
|
|
113
118
|
const target = ref.storeName;
|
|
119
|
+
const byBindingKey = entries.find((e) => e.bindingKey === target);
|
|
120
|
+
if (byBindingKey) return byBindingKey;
|
|
114
121
|
const exact = entries.find((e) => e.slug === target || e.id === target || e.name === target);
|
|
115
122
|
if (exact) return exact;
|
|
116
123
|
const norm = dataStoreSlug(target);
|
|
124
|
+
const byBindingKeyNorm = entries.find((e) => e.bindingKey === norm);
|
|
125
|
+
if (byBindingKeyNorm) return byBindingKeyNorm;
|
|
117
126
|
return entries.find(
|
|
118
127
|
(e) => e.slug === norm || typeof e.name === "string" && dataStoreSlug(e.name) === norm
|
|
119
128
|
);
|
|
@@ -324,6 +333,12 @@ async function createDataStore(options) {
|
|
|
324
333
|
if (!connectionString) {
|
|
325
334
|
const name = options?.storeName ?? options?.storeId;
|
|
326
335
|
const ref = name ? `data store "${name}"` : "a data store";
|
|
336
|
+
const resolved = options?.storeId || options?.storeName ? resolveDataStore({ storeId: options?.storeId, storeName: options?.storeName }) : void 0;
|
|
337
|
+
if (resolved?.storeType === "storage") {
|
|
338
|
+
throw new Error(
|
|
339
|
+
`${ref} is a storage store and has no SQL connection. Use DataStoreClient for storage operations (upload/download/list) instead of createDataStore.`
|
|
340
|
+
);
|
|
341
|
+
}
|
|
327
342
|
throw new Error(
|
|
328
343
|
`Could not resolve a connection string for ${ref}. Checked the STARDECK_DATA_STORES manifest, the legacy DATA_STORE_*_URL env var, and DATA_STORE_URL. Confirm the store is connected to this project, or pass connectionString in options.`
|
|
329
344
|
);
|
package/dist/server/index.mjs
CHANGED
|
@@ -41,9 +41,14 @@ function readDataStoreManifest() {
|
|
|
41
41
|
try {
|
|
42
42
|
const parsed = JSON.parse(raw);
|
|
43
43
|
if (!Array.isArray(parsed)) return [];
|
|
44
|
-
return parsed.filter(
|
|
45
|
-
(
|
|
46
|
-
|
|
44
|
+
return parsed.filter((e) => {
|
|
45
|
+
if (typeof e !== "object" || e === null) return false;
|
|
46
|
+
const entry = e;
|
|
47
|
+
if (typeof entry.id !== "string" || typeof entry.name !== "string" || typeof entry.slug !== "string") {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return entry.storeType === "storage" || typeof entry.url === "string";
|
|
51
|
+
});
|
|
47
52
|
} catch {
|
|
48
53
|
return [];
|
|
49
54
|
}
|
|
@@ -58,9 +63,13 @@ function resolveManifestEntry(entries, ref) {
|
|
|
58
63
|
}
|
|
59
64
|
if (ref.storeName) {
|
|
60
65
|
const target = ref.storeName;
|
|
66
|
+
const byBindingKey = entries.find((e) => e.bindingKey === target);
|
|
67
|
+
if (byBindingKey) return byBindingKey;
|
|
61
68
|
const exact = entries.find((e) => e.slug === target || e.id === target || e.name === target);
|
|
62
69
|
if (exact) return exact;
|
|
63
70
|
const norm = dataStoreSlug(target);
|
|
71
|
+
const byBindingKeyNorm = entries.find((e) => e.bindingKey === norm);
|
|
72
|
+
if (byBindingKeyNorm) return byBindingKeyNorm;
|
|
64
73
|
return entries.find(
|
|
65
74
|
(e) => e.slug === norm || typeof e.name === "string" && dataStoreSlug(e.name) === norm
|
|
66
75
|
);
|
|
@@ -271,6 +280,12 @@ async function createDataStore(options) {
|
|
|
271
280
|
if (!connectionString) {
|
|
272
281
|
const name = options?.storeName ?? options?.storeId;
|
|
273
282
|
const ref = name ? `data store "${name}"` : "a data store";
|
|
283
|
+
const resolved = options?.storeId || options?.storeName ? resolveDataStore({ storeId: options?.storeId, storeName: options?.storeName }) : void 0;
|
|
284
|
+
if (resolved?.storeType === "storage") {
|
|
285
|
+
throw new Error(
|
|
286
|
+
`${ref} is a storage store and has no SQL connection. Use DataStoreClient for storage operations (upload/download/list) instead of createDataStore.`
|
|
287
|
+
);
|
|
288
|
+
}
|
|
274
289
|
throw new Error(
|
|
275
290
|
`Could not resolve a connection string for ${ref}. Checked the STARDECK_DATA_STORES manifest, the legacy DATA_STORE_*_URL env var, and DATA_STORE_URL. Confirm the store is connected to this project, or pass connectionString in options.`
|
|
276
291
|
);
|