@potonz/shortlinks-manager-cf-d1 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Thomas Nguyen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # @potonz/shortlinks-manage-cf-d1
2
+
3
+ Short links manager backend using Cloudflare D1 database.
4
+
5
+ ## Setting up
6
+
7
+ You have to manually set up the DB for short links.
8
+ A function is provided for this, this should only be called once.
9
+
10
+ ```ts
11
+ import { env } from "cloudflare:workers";
12
+
13
+ const backend = createD1Backend(env.DB);
14
+ await backend.setupTables();
15
+ ```
@@ -0,0 +1,140 @@
1
+ // Generated by dts-bundle-generator v9.5.1
2
+
3
+ export interface D1Meta {
4
+ duration: number;
5
+ size_after: number;
6
+ rows_read: number;
7
+ rows_written: number;
8
+ last_row_id: number;
9
+ changed_db: boolean;
10
+ changes: number;
11
+ /**
12
+ * The region of the database instance that executed the query.
13
+ */
14
+ served_by_region?: string;
15
+ /**
16
+ * True if-and-only-if the database instance that executed the query was the primary.
17
+ */
18
+ served_by_primary?: boolean;
19
+ timings?: {
20
+ /**
21
+ * The duration of the SQL query execution by the database instance. It doesn't include any network time.
22
+ */
23
+ sql_duration_ms: number;
24
+ };
25
+ /**
26
+ * Number of total attempts to execute the query, due to automatic retries.
27
+ * Note: All other fields in the response like `timings` only apply to the last attempt.
28
+ */
29
+ total_attempts?: number;
30
+ }
31
+ export interface D1Response {
32
+ success: true;
33
+ meta: D1Meta & Record<string, unknown>;
34
+ error?: never;
35
+ }
36
+ export type D1Result<T = unknown> = D1Response & {
37
+ results: T[];
38
+ };
39
+ export interface D1ExecResult {
40
+ count: number;
41
+ duration: number;
42
+ }
43
+ export type D1SessionConstraint =
44
+ // Indicates that the first query should go to the primary, and the rest queries
45
+ // using the same D1DatabaseSession will go to any replica that is consistent with
46
+ // the bookmark maintained by the session (returned by the first query).
47
+ "first-primary"
48
+ // Indicates that the first query can go anywhere (primary or replica), and the rest queries
49
+ // using the same D1DatabaseSession will go to any replica that is consistent with
50
+ // the bookmark maintained by the session (returned by the first query).
51
+ | "first-unconstrained";
52
+ export type D1SessionBookmark = string;
53
+ declare abstract class D1Database {
54
+ prepare(query: string): D1PreparedStatement;
55
+ batch<T = unknown>(statements: D1PreparedStatement[]): Promise<D1Result<T>[]>;
56
+ exec(query: string): Promise<D1ExecResult>;
57
+ /**
58
+ * Creates a new D1 Session anchored at the given constraint or the bookmark.
59
+ * All queries executed using the created session will have sequential consistency,
60
+ * meaning that all writes done through the session will be visible in subsequent reads.
61
+ *
62
+ * @param constraintOrBookmark Either the session constraint or the explicit bookmark to anchor the created session.
63
+ */
64
+ withSession(constraintOrBookmark?: D1SessionBookmark | D1SessionConstraint): D1DatabaseSession;
65
+ /**
66
+ * @deprecated dump() will be removed soon, only applies to deprecated alpha v1 databases.
67
+ */
68
+ dump(): Promise<ArrayBuffer>;
69
+ }
70
+ declare abstract class D1DatabaseSession {
71
+ prepare(query: string): D1PreparedStatement;
72
+ batch<T = unknown>(statements: D1PreparedStatement[]): Promise<D1Result<T>[]>;
73
+ /**
74
+ * @returns The latest session bookmark across all executed queries on the session.
75
+ * If no query has been executed yet, `null` is returned.
76
+ */
77
+ getBookmark(): D1SessionBookmark | null;
78
+ }
79
+ declare abstract class D1PreparedStatement {
80
+ bind(...values: unknown[]): D1PreparedStatement;
81
+ first<T = unknown>(colName: string): Promise<T | null>;
82
+ first<T = Record<string, unknown>>(): Promise<T | null>;
83
+ run<T = Record<string, unknown>>(): Promise<D1Result<T>>;
84
+ all<T = Record<string, unknown>>(): Promise<D1Result<T>>;
85
+ raw<T = unknown[]>(options: {
86
+ columnNames: true;
87
+ }): Promise<[
88
+ string[],
89
+ ...T[]
90
+ ]>;
91
+ raw<T = unknown[]>(options?: {
92
+ columnNames?: false;
93
+ }): Promise<T[]>;
94
+ }
95
+ // Generated by dts-bundle-generator v9.5.1
96
+ export interface IShortLinksManagerBackend {
97
+ /**
98
+ * Initialise any logic before the manager can do its thing. E.g. setting up tables.
99
+ * Run once when {@link createManager} is called
100
+ */
101
+ init?: () => unknown;
102
+ /**
103
+ * Get target URL for the given short ID
104
+ * @param {string} shortId
105
+ * @returns the short ID or null if not found
106
+ */
107
+ getTargetUrl: (shortId: string) => string | null | Promise<string | null>;
108
+ /**
109
+ * Create a short link map with the given short ID and target URL
110
+ * @param {string} shortId
111
+ * @param {string} targetUrl
112
+ */
113
+ createShortLink: (shortId: string, targetUrl: string) => void | Promise<void>;
114
+ /**
115
+ * Check the provided list of short IDs and return the ones that already exist.
116
+ * @param {string[]} shortIds
117
+ */
118
+ checkShortIdsExist: (shortIds: string[]) => string[] | Promise<string[]>;
119
+ /**
120
+ * Update last accessed time to current timestamp
121
+ * @param shortId
122
+ */
123
+ updateShortLinkLastAccessTime(shortId: string): void | Promise<void>;
124
+ /**
125
+ * Remove unused links that are older than the given maxAge
126
+ * @param maxAge number of days the record should be kept
127
+ */
128
+ cleanUnusedLinks(maxAge: number): void | Promise<void>;
129
+ }
130
+ export interface IShortLinksManagerD1Backend extends IShortLinksManagerBackend {
131
+ setupTables: () => Promise<void>;
132
+ }
133
+ export declare function createD1Backend(db: D1Database): IShortLinksManagerD1Backend;
134
+ declare const _default: {};
135
+
136
+ export {
137
+ _default as default,
138
+ };
139
+
140
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,47 @@
1
+ /* MIT License
2
+
3
+ Copyright (c) 2025 Thomas Nguyen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+ */
23
+ /*! *****************************************************************************
24
+ Copyright (c) Cloudflare. All rights reserved.
25
+ Copyright (c) Microsoft Corporation. All rights reserved.
26
+
27
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use
28
+ this file except in compliance with the License. You may obtain a copy of the
29
+ License at http://www.apache.org/licenses/LICENSE-2.0
30
+ THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
31
+ KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
32
+ WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
33
+ MERCHANTABLITY OR NON-INFRINGEMENT.
34
+ See the Apache Version 2.0 License for specific language governing permissions
35
+ and limitations under the License.
36
+ ***************************************************************************** */function F(j){let w=null,y=null,z=null,B=null,C=null;return{async setupTables(){await j.prepare(`
37
+ CREATE TABLE IF NOT EXISTS sl_links_map (
38
+ short_id VARCHAR(255) NOT NULL PRIMARY KEY,
39
+ target_url VARCHAR(65535) NOT NULL,
40
+ last_accessed_at DATETIME DEFAULT CURRENT_TIMESTAMP,
41
+ created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
42
+ );
43
+
44
+ CREATE INDEX IF NOT EXISTS idx_sl_links_map_last_accessed_at ON sl_links_map(last_accessed_at);
45
+
46
+ PRAGMA optimize;
47
+ `).run()},async getTargetUrl(f){if(!w)w=j.prepare("SELECT target_url FROM sl_links_map WHERE short_id = ? LIMIT 1");return(await w.bind(f).first())?.target_url??null},async createShortLink(f,q){if(!z)z=j.prepare("INSERT INTO sl_links_map (short_id, target_url) VALUES (?, ?)");await z.bind(f,q).run()},async checkShortIdsExist(f){if(!y){let D=Array.from("?".repeat(f.length)).join(",");y=j.prepare(`SELECT short_id FROM sl_links_map WHERE short_id IN (${D})`)}let q=await y.bind(...f).all();if(!q.success)return[];return q.results.map((D)=>D.short_id)},async updateShortLinkLastAccessTime(f){if(!B)B=j.prepare("UPDATE sl_links_map SET last_accessed_at = CURRENT_TIMESTAMP WHERE short_id = ?");await B.bind(f).run()},async cleanUnusedLinks(f){if(!C)C=j.prepare("DELETE FROM sl_links_map WHERE last_accessed_at < datetime(CURRENT_TIMESTAMP, ?)");await C.bind(`-${f} days`).run()}}}var J={};export{J as default,F as createD1Backend};
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@potonz/shortlinks-manager-cf-d1",
3
+ "description": "Short links manager extension for Cloudflare D1",
4
+ "author": {
5
+ "name": "Thomas Nguyen",
6
+ "email": "tom@tomng.dev"
7
+ },
8
+ "homepage": "https://github.com/potonz/shortlinks-manager",
9
+ "repository": {
10
+ "url": "git+https://github.com/potonz/shortlinks-manager.git",
11
+ "type": "git"
12
+ },
13
+ "version": "0.1.0",
14
+ "type": "module",
15
+ "license": "MIT",
16
+ "dependencies": {
17
+ "@potonz/shortlinks-manager": "0.1.0"
18
+ },
19
+ "main": "./dist/index.js",
20
+ "module": "./dist/index.js",
21
+ "types": "./dist/index.d.ts",
22
+ "exports": {
23
+ ".": {
24
+ "import": "./dist/index.js",
25
+ "require": "./dist/index.js",
26
+ "types": "./dist/index.d.ts"
27
+ }
28
+ },
29
+ "files": [
30
+ "dist"
31
+ ],
32
+ "publishConfig": {
33
+ "access": "public"
34
+ }
35
+ }