@rebasepro/server 0.16.0 → 0.16.1-canary.g2d1aec8
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/api/contract-routes.d.ts +1 -1
- package/dist/api/errors.d.ts +1 -1
- package/dist/api/index.d.ts +3 -3
- package/dist/api/live-schema-routes.d.ts +111 -0
- package/dist/api/logs-routes.d.ts +1 -1
- package/dist/api/mount.d.ts +41 -0
- package/dist/api/rest/api-generator.d.ts +2 -2
- package/dist/api/rest/index.d.ts +1 -1
- package/dist/api/rest/query-parser.d.ts +1 -1
- package/dist/api/schema-editor-routes.d.ts +1 -1
- package/dist/api/types.d.ts +3 -4
- package/dist/{schema-editor-routes-CV9k0w3G.js → ast-schema-editor-BpFYpT38.js} +2 -39
- package/dist/ast-schema-editor-BpFYpT38.js.map +1 -0
- package/dist/auth/adapter-middleware.d.ts +2 -2
- package/dist/auth/admin-roles-route.d.ts +2 -2
- package/dist/auth/admin-user-ops.d.ts +3 -3
- package/dist/auth/admin-users-route.d.ts +4 -4
- package/dist/auth/api-keys/api-key-middleware.d.ts +2 -2
- package/dist/auth/api-keys/api-key-permission-guard.d.ts +1 -1
- package/dist/auth/api-keys/api-key-routes.d.ts +2 -2
- package/dist/auth/api-keys/api-key-store.d.ts +1 -1
- package/dist/auth/api-keys/index.d.ts +9 -9
- package/dist/auth/apple-oauth.d.ts +2 -2
- package/dist/auth/auth-hooks.d.ts +3 -3
- package/dist/auth/bitbucket-oauth.d.ts +2 -2
- package/dist/auth/builtin-auth-adapter.d.ts +7 -4
- package/dist/auth/captcha.d.ts +86 -0
- package/dist/auth/cookie-utils.d.ts +2 -2
- package/dist/auth/discord-oauth.d.ts +2 -2
- package/dist/auth/facebook-oauth.d.ts +2 -2
- package/dist/auth/github-oauth.d.ts +2 -2
- package/dist/auth/gitlab-oauth.d.ts +2 -2
- package/dist/auth/google-oauth.d.ts +1 -1
- package/dist/auth/index.d.ts +56 -54
- package/dist/auth/jwks-routes.d.ts +1 -1
- package/dist/auth/jwt.d.ts +1 -1
- package/dist/auth/linkedin-oauth.d.ts +2 -2
- package/dist/auth/magic-link-routes.d.ts +10 -3
- package/dist/auth/mfa-gate.d.ts +1 -1
- package/dist/auth/mfa-routes.d.ts +3 -3
- package/dist/auth/microsoft-oauth.d.ts +2 -2
- package/dist/auth/middleware.d.ts +5 -5
- package/dist/auth/rate-limiter.d.ts +2 -2
- package/dist/auth/require-auth.d.ts +1 -1
- package/dist/auth/reset-password-admin.d.ts +4 -4
- package/dist/auth/routes.d.ts +13 -4
- package/dist/auth/session-routes.d.ts +3 -3
- package/dist/auth/slack-oauth.d.ts +2 -2
- package/dist/auth/spotify-oauth.d.ts +2 -2
- package/dist/auth/token-revocation.d.ts +2 -2
- package/dist/auth/twitter-oauth.d.ts +2 -2
- package/dist/{auth-5Et5mnUA.js → auth-C74dqR2B.js} +250 -15
- package/dist/auth-C74dqR2B.js.map +1 -0
- package/dist/backup/backup-common.d.ts +1 -1
- package/dist/backup/backup-routes.d.ts +3 -3
- package/dist/backup/index.d.ts +3 -3
- package/dist/{backup-C6ljYVTp.js → backup-BJ86ah4T.js} +2 -2
- package/dist/{backup-C6ljYVTp.js.map → backup-BJ86ah4T.js.map} +1 -1
- package/dist/boot/boot.d.ts +5 -5
- package/dist/boot/bundle.d.ts +1 -1
- package/dist/boot/driver.d.ts +1 -1
- package/dist/boot/env.d.ts +13 -1
- package/dist/boot/options.d.ts +30 -6
- package/dist/boot/role.d.ts +3 -2
- package/dist/boot/sources.d.ts +1 -1
- package/dist/collections/BackendCollectionRegistry.d.ts +1 -1
- package/dist/collections/loader.d.ts +1 -1
- package/dist/{contract-routes-DZ-LBpSL.js → contract-routes-BEq7euZg.js} +2 -2
- package/dist/contract-routes-BEq7euZg.js.map +1 -0
- package/dist/cron/cron-routes.d.ts +2 -2
- package/dist/cron/cron-scheduler.d.ts +2 -2
- package/dist/cron/index.d.ts +8 -8
- package/dist/{cron-loader-YhhQeVBM.js → cron-loader-BMvtW6-J.js} +2 -2
- package/dist/{cron-loader-YhhQeVBM.js.map → cron-loader-BMvtW6-J.js.map} +1 -1
- package/dist/{cron-routes-maM_RlUu.js → cron-routes-BvYk-Kmi.js} +2 -2
- package/dist/{cron-routes-maM_RlUu.js.map → cron-routes-BvYk-Kmi.js.map} +1 -1
- package/dist/{cron-scheduler-DIpYBmZP.js → cron-scheduler-Buf-uVam.js} +2 -2
- package/dist/{cron-scheduler-DIpYBmZP.js.map → cron-scheduler-Buf-uVam.js.map} +1 -1
- package/dist/{cron-store-DfH_4Cd9.js → cron-store-CyF-oInV.js} +3 -3
- package/dist/{cron-store-DfH_4Cd9.js.map → cron-store-CyF-oInV.js.map} +1 -1
- package/dist/{ddl-bootstrap-Cywoj8Ta.js → ddl-bootstrap-DgSnERYN.js} +17 -3
- package/dist/ddl-bootstrap-DgSnERYN.js.map +1 -0
- package/dist/dev-secrets.d.ts +52 -0
- package/dist/email/dev-sink.d.ts +67 -0
- package/dist/email/index.d.ts +9 -7
- package/dist/email/link-base.d.ts +1 -1
- package/dist/email/smtp-email-service.d.ts +1 -1
- package/dist/env.d.ts +1 -1
- package/dist/{errors-EBYiaJ2E.js → errors-D_LwNKRM.js} +5 -5
- package/dist/errors-D_LwNKRM.js.map +1 -0
- package/dist/{function-loader-DDS1v7YX.js → function-loader-BrLmC_-y.js} +3 -3
- package/dist/{function-loader-DDS1v7YX.js.map → function-loader-BrLmC_-y.js.map} +1 -1
- package/dist/functions/context.d.ts +141 -0
- package/dist/functions/define-function.d.ts +1 -1
- package/dist/functions/function-routes.d.ts +2 -2
- package/dist/functions/guards.d.ts +76 -0
- package/dist/functions/index.d.ts +96 -5
- package/dist/functions/index.js +919 -0
- package/dist/functions/index.js.map +1 -0
- package/dist/functions/internal.d.ts +26 -0
- package/dist/functions/proxy.d.ts +1 -1
- package/dist/functions/request-timeout.d.ts +9 -1
- package/dist/functions/runtime-env.d.ts +92 -0
- package/dist/functions/wait-until.d.ts +74 -0
- package/dist/history/history-routes.d.ts +2 -2
- package/dist/history/index.d.ts +1 -1
- package/dist/index.d.ts +63 -54
- package/dist/index.es.js +2183 -164
- package/dist/index.es.js.map +1 -1
- package/dist/init/docs.d.ts +1 -1
- package/dist/init/middlewares.d.ts +1 -1
- package/dist/init/shutdown.d.ts +4 -0
- package/dist/init/storage.d.ts +1 -1
- package/dist/init/surfaces.d.ts +10 -0
- package/dist/init.d.ts +104 -18
- package/dist/jobs/index.d.ts +5 -5
- package/dist/{jobs-CyOKXXlu.js → jobs-Bn6nhY8J.js} +3 -3
- package/dist/{jobs-CyOKXXlu.js.map → jobs-Bn6nhY8J.js.map} +1 -1
- package/dist/{jwt-DxH9fLPt.js → jwt-BbJi0TR0.js} +2 -2
- package/dist/{jwt-DxH9fLPt.js.map → jwt-BbJi0TR0.js.map} +1 -1
- package/dist/{logger-DfvF_8r-.js → logger-TdvXIGqR.js} +101 -8
- package/dist/logger-TdvXIGqR.js.map +1 -0
- package/dist/metrics/index.d.ts +1 -1
- package/dist/{proxy-Bj5DVllb.js → proxy-QJKSS-CV.js} +5 -3
- package/dist/{proxy-Bj5DVllb.js.map → proxy-QJKSS-CV.js.map} +1 -1
- package/dist/{request-timeout-BuFoEKwT.js → request-timeout-OofPCHQT.js} +17 -3
- package/dist/request-timeout-OofPCHQT.js.map +1 -0
- package/dist/rls-audit/index.d.ts +111 -0
- package/dist/schema-edit/apply-schema-change.d.ts +141 -0
- package/dist/schema-edit/github-repository.d.ts +67 -0
- package/dist/schema-edit/local-git-repository.d.ts +28 -0
- package/dist/schema-edit/project-root.d.ts +29 -0
- package/dist/schema-edit/remote-source.d.ts +25 -0
- package/dist/schema-edit/schema-edit-permissions.d.ts +129 -0
- package/dist/schema-editor-routes-yh2cQcdJ.js +44 -0
- package/dist/schema-editor-routes-yh2cQcdJ.js.map +1 -0
- package/dist/services/webhook-service.d.ts +1 -1
- package/dist/singleton.d.ts +7 -0
- package/dist/storage/GCSStorageController.d.ts +1 -1
- package/dist/storage/LocalStorageController.d.ts +1 -1
- package/dist/storage/S3StorageController.d.ts +1 -1
- package/dist/storage/cache-headers.d.ts +87 -0
- package/dist/storage/index.d.ts +11 -11
- package/dist/storage/policies.d.ts +88 -0
- package/dist/storage/range.d.ts +63 -0
- package/dist/storage/routes.d.ts +3 -3
- package/dist/storage/storage-registry.d.ts +1 -1
- package/dist/storage/tus-handler.d.ts +2 -2
- package/dist/utils/host.d.ts +58 -0
- package/dist/utils/logger.d.ts +0 -15
- package/dist/utils/request-id.d.ts +1 -1
- package/functions/package.json +24 -0
- package/package.json +13 -7
- package/dist/auth-5Et5mnUA.js.map +0 -1
- package/dist/contract-routes-DZ-LBpSL.js.map +0 -1
- package/dist/ddl-bootstrap-Cywoj8Ta.js.map +0 -1
- package/dist/errors-EBYiaJ2E.js.map +0 -1
- package/dist/logger-DfvF_8r-.js.map +0 -1
- package/dist/request-timeout-BuFoEKwT.js.map +0 -1
- package/dist/schema-editor-routes-CV9k0w3G.js.map +0 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { SchemaEditRepository } from "./apply-schema-change.js";
|
|
2
|
+
export interface LocalGitOptions {
|
|
3
|
+
/** Absolute path to the working tree the collections live in. */
|
|
4
|
+
root: string;
|
|
5
|
+
/**
|
|
6
|
+
* Who the commit is attributed to. Defaults to the repository's own git
|
|
7
|
+
* config, which is right for a developer's machine and wrong for a server
|
|
8
|
+
* — a panel edit should say which account made it.
|
|
9
|
+
*/
|
|
10
|
+
author?: {
|
|
11
|
+
name: string;
|
|
12
|
+
email: string;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export declare class GitCommandError extends Error {
|
|
16
|
+
constructor(command: string, detail: string);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The top of the working tree containing `startDir`, or undefined.
|
|
20
|
+
*
|
|
21
|
+
* Resolved by asking git rather than by walking for a `.git`, because a
|
|
22
|
+
* worktree's `.git` is a file and a submodule's is neither where nor what a
|
|
23
|
+
* naive walk expects.
|
|
24
|
+
*/
|
|
25
|
+
export declare function findRepositoryRoot(startDir: string): Promise<string | undefined>;
|
|
26
|
+
/** True when `root` is inside a git working tree. */
|
|
27
|
+
export declare function isGitRepository(root: string): Promise<boolean>;
|
|
28
|
+
export declare function createLocalGitRepository(options: LocalGitOptions): SchemaEditRepository;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type SchemaCommitPaths } from "@rebasepro/types";
|
|
2
|
+
/**
|
|
3
|
+
* The nearest ancestor of `startDir` holding a `rebase.json`.
|
|
4
|
+
*
|
|
5
|
+
* Bounded, like the storage-source loader it mirrors: an unbounded walk from a
|
|
6
|
+
* misconfigured path climbs to the filesystem root and reads whatever it finds
|
|
7
|
+
* there. `undefined` when there is none, which is a project that predates the
|
|
8
|
+
* file — the caller then keeps the historical behaviour rather than guessing.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Where a scaffolded project keeps its collection source, project-relative.
|
|
12
|
+
*
|
|
13
|
+
* A bundle's own collections directory is compiled output, so nothing on the
|
|
14
|
+
* running machine points at this. A deployment committing to a repository states
|
|
15
|
+
* it, and this is the default it states nothing against.
|
|
16
|
+
*/
|
|
17
|
+
export declare const DEFAULT_COLLECTIONS_PATH = "config/collections";
|
|
18
|
+
export declare function findProjectRoot(startDir: string, levels?: number): string | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* The generated-artifact paths for a project, expressed relative to the
|
|
21
|
+
* repository that will hold the commit.
|
|
22
|
+
*
|
|
23
|
+
* Returns `undefined` when there is nothing to correct — no project marker, or
|
|
24
|
+
* a project that *is* the repository — so the caller passes no override and the
|
|
25
|
+
* defaults stand. Saying "no change needed" is different from saying
|
|
26
|
+
* "the change is a no-op prefix", and only the first leaves the existing
|
|
27
|
+
* behaviour untouched for every project that already worked.
|
|
28
|
+
*/
|
|
29
|
+
export declare function commitPathsFor(collectionsDir: string, repositoryRoot: string): Partial<SchemaCommitPaths> | undefined;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { SchemaChangeFile } from "@rebasepro/types";
|
|
2
|
+
import type { SchemaEditRepository } from "./apply-schema-change.js";
|
|
3
|
+
export interface RemoteSourceOptions {
|
|
4
|
+
repository: SchemaEditRepository;
|
|
5
|
+
/**
|
|
6
|
+
* Where the collection *source* lives in the repository, as a repo-relative
|
|
7
|
+
* posix path — `config/collections`, or `app/config/collections` for a
|
|
8
|
+
* project in a subdirectory.
|
|
9
|
+
*
|
|
10
|
+
* Not derivable from the bundle: its `collectionsDir` points at compiled
|
|
11
|
+
* output, which is a different directory holding different files.
|
|
12
|
+
*/
|
|
13
|
+
collectionsPath: string;
|
|
14
|
+
/** Applies the edit. Injected so this module needs no `ts-morph`. */
|
|
15
|
+
edit: (collectionsDir: string, collectionId: string, collection: Record<string, unknown>) => Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Fetch, rewrite, and return the changed file — without leaving anything behind.
|
|
19
|
+
*
|
|
20
|
+
* The scratch directory is removed on every path, including the failing one. It
|
|
21
|
+
* holds a copy of the customer's collection source, and a temp directory that
|
|
22
|
+
* accumulates those on a long-running server is a slow leak of exactly the
|
|
23
|
+
* thing worth not leaking.
|
|
24
|
+
*/
|
|
25
|
+
export declare function rewriteRemoteCollection(options: RemoteSourceOptions, collectionId: string, collection: Record<string, unknown>): Promise<SchemaChangeFile[]>;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who may plan a schema change, and who may apply one.
|
|
3
|
+
*
|
|
4
|
+
* Being an admin is one privilege. Applying a schema change is two: it alters
|
|
5
|
+
* the database, and it writes a commit into the project's repository under
|
|
6
|
+
* somebody's name. `requireAdmin` in front of both routes answers the first
|
|
7
|
+
* question and never asks the second.
|
|
8
|
+
*
|
|
9
|
+
* `admin-roles.ts` says the rest of it: `schema-admin` is administrative
|
|
10
|
+
* "by any definition that matters", and "if a genuinely lesser role is added
|
|
11
|
+
* later, it does not belong in this list — it belongs in a capability check of
|
|
12
|
+
* its own". This is that check.
|
|
13
|
+
*
|
|
14
|
+
* ## The split that matters is not between roles
|
|
15
|
+
*
|
|
16
|
+
* It is between a person and a machine.
|
|
17
|
+
*
|
|
18
|
+
* `plan` has no side effects. It reads the collections, reads the database
|
|
19
|
+
* catalogue, and answers what would happen. Anyone already through the admin
|
|
20
|
+
* gate may do it, and a CI job that wants to know whether a proposed collection
|
|
21
|
+
* change is applicable is a *good* use of this API.
|
|
22
|
+
*
|
|
23
|
+
* `apply` commits. The commit carries an author, and the author is the point —
|
|
24
|
+
* the code that builds it says so: a schema change with an author and a diff in
|
|
25
|
+
* the project's history is the thing worth having, and an anonymous one is just
|
|
26
|
+
* a commit. A service key has no author. `api-key:7c3f…` has no author. Letting
|
|
27
|
+
* either write to the project's source produces exactly the unattributable
|
|
28
|
+
* history the feature exists to replace, and does it with a credential that is
|
|
29
|
+
* likely to be sitting in a CI environment variable.
|
|
30
|
+
*
|
|
31
|
+
* So machines plan by default and do not apply. An operator who genuinely wants
|
|
32
|
+
* an automated schema change — a migration pipeline, say — turns it on
|
|
33
|
+
* deliberately and gets a commit that says plainly which key made it.
|
|
34
|
+
*/
|
|
35
|
+
/** What a caller is allowed to do with the live schema editor. */
|
|
36
|
+
export interface SchemaEditCapabilities {
|
|
37
|
+
/** Preview a change. No side effects. */
|
|
38
|
+
plan: boolean;
|
|
39
|
+
/** Commit the change and run the DDL. */
|
|
40
|
+
apply: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Why `apply` is denied, when it is and `plan` is not.
|
|
43
|
+
*
|
|
44
|
+
* Carried so the panel can grey out the button *and say why*, rather than
|
|
45
|
+
* letting somebody read a plan, decide, press, and only then be refused.
|
|
46
|
+
*/
|
|
47
|
+
reason?: string;
|
|
48
|
+
/** A stable code for the refusal, for clients that branch rather than read. */
|
|
49
|
+
code?: string;
|
|
50
|
+
}
|
|
51
|
+
/** The kind of caller, which is what the `apply` decision turns on. */
|
|
52
|
+
export type PrincipalKind = "person" | "machine" | "anonymous";
|
|
53
|
+
export interface SchemaEditPrincipal {
|
|
54
|
+
kind: PrincipalKind;
|
|
55
|
+
/** Empty for an anonymous caller. */
|
|
56
|
+
uid: string;
|
|
57
|
+
roles: string[];
|
|
58
|
+
/** How the machine identified itself, for the refusal message. */
|
|
59
|
+
machineKind?: "service-key" | "api-key";
|
|
60
|
+
}
|
|
61
|
+
/** Read the caller off the request context's `user`. */
|
|
62
|
+
export declare function classifyPrincipal(user: unknown): SchemaEditPrincipal;
|
|
63
|
+
/**
|
|
64
|
+
* A repository that is not on this machine.
|
|
65
|
+
*
|
|
66
|
+
* Configured by a deployment running built output — every Cloud tenant, and any
|
|
67
|
+
* self-host serving a bundle. Without it, live schema editing needs the source
|
|
68
|
+
* on disk and refuses when there is none.
|
|
69
|
+
*/
|
|
70
|
+
export interface RemoteRepositoryConfig {
|
|
71
|
+
kind: "github";
|
|
72
|
+
owner: string;
|
|
73
|
+
repo: string;
|
|
74
|
+
/** Defaults to `main`. */
|
|
75
|
+
branch?: string;
|
|
76
|
+
/**
|
|
77
|
+
* Where the collection **source** lives in that repository, repo-relative.
|
|
78
|
+
* Defaults to `config/collections`.
|
|
79
|
+
*
|
|
80
|
+
* Not derivable from the running bundle, whose collections directory holds
|
|
81
|
+
* compiled output — a different directory with different files.
|
|
82
|
+
*/
|
|
83
|
+
collectionsPath?: string;
|
|
84
|
+
/**
|
|
85
|
+
* A GitHub App installation, or a token.
|
|
86
|
+
*
|
|
87
|
+
* The app is for a control plane holding one key across many projects; the
|
|
88
|
+
* token is for a single self-hoster who would otherwise have to stand one
|
|
89
|
+
* up to let their own server commit to their own repository.
|
|
90
|
+
*/
|
|
91
|
+
auth: {
|
|
92
|
+
kind: "app";
|
|
93
|
+
appId: string;
|
|
94
|
+
privateKey: string;
|
|
95
|
+
installationId: string;
|
|
96
|
+
} | {
|
|
97
|
+
kind: "token";
|
|
98
|
+
token: string;
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
export interface SchemaEditPolicy {
|
|
102
|
+
/**
|
|
103
|
+
* Let a service key or an API key commit a schema change.
|
|
104
|
+
*
|
|
105
|
+
* Off by default. On, the commit is attributed to the credential rather
|
|
106
|
+
* than to a person, and says so — see {@link machineCommitAuthor}.
|
|
107
|
+
*/
|
|
108
|
+
allowMachineApply?: boolean;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* What this caller may do.
|
|
112
|
+
*
|
|
113
|
+
* Assumes the admin gate has already run — this refines that decision rather
|
|
114
|
+
* than replacing it, and an anonymous caller should never have reached here.
|
|
115
|
+
* Handled anyway, because a capability function that trusts its caller to have
|
|
116
|
+
* checked is one bad refactor away from granting everything.
|
|
117
|
+
*/
|
|
118
|
+
export declare function schemaEditCapabilities(principal: SchemaEditPrincipal, policy?: SchemaEditPolicy): SchemaEditCapabilities;
|
|
119
|
+
/**
|
|
120
|
+
* The git identity for a machine that has been allowed to apply.
|
|
121
|
+
*
|
|
122
|
+
* Named for what it is. An operator reading `git log` a month from now should
|
|
123
|
+
* be able to tell a change somebody made from one a pipeline made, and a
|
|
124
|
+
* credential wearing a person-shaped name is how that distinction is lost.
|
|
125
|
+
*/
|
|
126
|
+
export declare function machineCommitAuthor(principal: SchemaEditPrincipal): {
|
|
127
|
+
name: string;
|
|
128
|
+
email: string;
|
|
129
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from "module";
|
|
2
|
+
import "process";
|
|
3
|
+
__createRequire(import.meta.url);
|
|
4
|
+
import { n as errorHandler } from "./errors-D_LwNKRM.js";
|
|
5
|
+
import { AstSchemaEditor } from "./ast-schema-editor-BpFYpT38.js";
|
|
6
|
+
import { Hono } from "hono";
|
|
7
|
+
//#region src/api/schema-editor-routes.ts
|
|
8
|
+
function createSchemaEditorRoutes(collectionsDir) {
|
|
9
|
+
const router = new Hono();
|
|
10
|
+
router.onError(errorHandler);
|
|
11
|
+
const editor = new AstSchemaEditor(collectionsDir);
|
|
12
|
+
router.post("/property/save", async (c) => {
|
|
13
|
+
const { collectionId, propertyKey, propertyConfig } = await c.req.json();
|
|
14
|
+
await editor.saveProperty(collectionId, propertyKey, propertyConfig);
|
|
15
|
+
return c.json({ success: true });
|
|
16
|
+
});
|
|
17
|
+
router.post("/property/delete", async (c) => {
|
|
18
|
+
const { collectionId, propertyKey } = await c.req.json();
|
|
19
|
+
await editor.deleteProperty(collectionId, propertyKey);
|
|
20
|
+
return c.json({ success: true });
|
|
21
|
+
});
|
|
22
|
+
/**
|
|
23
|
+
* `partial: true` means "this payload is what changed", not "this is the
|
|
24
|
+
* collection". Without it a one-key patch — which is what adding a column
|
|
25
|
+
* posts — is read as a whole-collection save and deletes everything it does
|
|
26
|
+
* not mention, `securityRules` included. Absent, it defaults to a full save,
|
|
27
|
+
* so an older panel keeps the behaviour it was written against.
|
|
28
|
+
*/
|
|
29
|
+
router.post("/collection/save", async (c) => {
|
|
30
|
+
const { collectionId, collectionData, partial } = await c.req.json();
|
|
31
|
+
await editor.saveCollection(collectionId, collectionData, { partial: partial === true });
|
|
32
|
+
return c.json({ success: true });
|
|
33
|
+
});
|
|
34
|
+
router.post("/collection/delete", async (c) => {
|
|
35
|
+
const { collectionId } = await c.req.json();
|
|
36
|
+
await editor.deleteCollection(collectionId);
|
|
37
|
+
return c.json({ success: true });
|
|
38
|
+
});
|
|
39
|
+
return router;
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { createSchemaEditorRoutes };
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=schema-editor-routes-yh2cQcdJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-editor-routes-yh2cQcdJ.js","names":[],"sources":["../src/api/schema-editor-routes.ts"],"sourcesContent":["import { Hono } from \"hono\";\nimport { AstSchemaEditor } from \"./ast-schema-editor\";\nimport { errorHandler } from \"./errors\";\nimport { HonoEnv } from \"./types\";\n\nexport function createSchemaEditorRoutes(collectionsDir: string): Hono<HonoEnv> {\n const router = new Hono<HonoEnv>();\n router.onError(errorHandler);\n const editor = new AstSchemaEditor(collectionsDir);\n\n router.post(\"/property/save\", async (c) => {\n const body = await c.req.json();\n const { collectionId, propertyKey, propertyConfig } = body;\n await editor.saveProperty(collectionId, propertyKey, propertyConfig);\n return c.json({ success: true });\n });\n\n router.post(\"/property/delete\", async (c) => {\n const body = await c.req.json();\n const { collectionId, propertyKey } = body;\n await editor.deleteProperty(collectionId, propertyKey);\n return c.json({ success: true });\n });\n\n /**\n * `partial: true` means \"this payload is what changed\", not \"this is the\n * collection\". Without it a one-key patch — which is what adding a column\n * posts — is read as a whole-collection save and deletes everything it does\n * not mention, `securityRules` included. Absent, it defaults to a full save,\n * so an older panel keeps the behaviour it was written against.\n */\n router.post(\"/collection/save\", async (c) => {\n const body = await c.req.json();\n const { collectionId, collectionData, partial } = body;\n await editor.saveCollection(collectionId, collectionData, { partial: partial === true });\n return c.json({ success: true });\n });\n\n router.post(\"/collection/delete\", async (c) => {\n const body = await c.req.json();\n const { collectionId } = body;\n await editor.deleteCollection(collectionId);\n return c.json({ success: true });\n });\n\n return router;\n}\n\n"],"mappings":";;;;;;;AAKA,SAAgB,yBAAyB,gBAAuC;CAC5E,MAAM,SAAS,IAAI,KAAc;CACjC,OAAO,QAAQ,YAAY;CAC3B,MAAM,SAAS,IAAI,gBAAgB,cAAc;CAEjD,OAAO,KAAK,kBAAkB,OAAO,MAAM;EAEvC,MAAM,EAAE,cAAc,aAAa,mBAAmB,MADnC,EAAE,IAAI,KAAK;EAE9B,MAAM,OAAO,aAAa,cAAc,aAAa,cAAc;EACnE,OAAO,EAAE,KAAK,EAAE,SAAS,KAAK,CAAC;CACnC,CAAC;CAED,OAAO,KAAK,oBAAoB,OAAO,MAAM;EAEzC,MAAM,EAAE,cAAc,gBAAgB,MADnB,EAAE,IAAI,KAAK;EAE9B,MAAM,OAAO,eAAe,cAAc,WAAW;EACrD,OAAO,EAAE,KAAK,EAAE,SAAS,KAAK,CAAC;CACnC,CAAC;;;;;;;;CASD,OAAO,KAAK,oBAAoB,OAAO,MAAM;EAEzC,MAAM,EAAE,cAAc,gBAAgB,YAAY,MAD/B,EAAE,IAAI,KAAK;EAE9B,MAAM,OAAO,eAAe,cAAc,gBAAgB,EAAE,SAAS,YAAY,KAAK,CAAC;EACvF,OAAO,EAAE,KAAK,EAAE,SAAS,KAAK,CAAC;CACnC,CAAC;CAED,OAAO,KAAK,sBAAsB,OAAO,MAAM;EAE3C,MAAM,EAAE,iBAAiB,MADN,EAAE,IAAI,KAAK;EAE9B,MAAM,OAAO,iBAAiB,YAAY;EAC1C,OAAO,EAAE,KAAK,EAAE,SAAS,KAAK,CAAC;CACnC,CAAC;CAED,OAAO;AACX"}
|
package/dist/singleton.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import type { RebaseServerClient } from "@rebasepro/types";
|
|
2
|
+
/**
|
|
3
|
+
* @internal Register the per-call resolver described on {@link RESOLVER_SLOT}.
|
|
4
|
+
*
|
|
5
|
+
* For runtime adapters, not for application code. Pass `null` to unregister.
|
|
6
|
+
* Returns the previous resolver so an adapter can restore it.
|
|
7
|
+
*/
|
|
8
|
+
export declare function _setRebaseResolver(resolve: (() => RebaseServerClient | null) | null): (() => RebaseServerClient | null) | null;
|
|
2
9
|
/**
|
|
3
10
|
* @internal Called once during server initialization to set the backing instance.
|
|
4
11
|
* This is invoked by `initializeRebaseBackend()` — never call it manually.
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* optional peer dependency — users who don't need GCS never pay for the
|
|
6
6
|
* import cost or need it installed.
|
|
7
7
|
*/
|
|
8
|
-
import { StorageController, GCSStorageConfig } from "./types";
|
|
8
|
+
import { StorageController, GCSStorageConfig } from "./types.js";
|
|
9
9
|
import { UploadFileProps, UploadFileResult, DownloadConfig, StorageListResult } from "@rebasepro/types";
|
|
10
10
|
/**
|
|
11
11
|
* Google Cloud Storage implementation of `StorageController`.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Local filesystem storage controller
|
|
3
3
|
*/
|
|
4
|
-
import { StorageController, LocalStorageConfig } from "./types";
|
|
4
|
+
import { StorageController, LocalStorageConfig } from "./types.js";
|
|
5
5
|
import { UploadFileProps, UploadFileResult, DownloadConfig, StorageListResult } from "@rebasepro/types";
|
|
6
6
|
/**
|
|
7
7
|
* Bucket used when a call names none.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* S3-compatible storage controller (works with AWS S3 and MinIO)
|
|
3
3
|
*/
|
|
4
|
-
import { S3StorageConfig, StorageController } from "./types";
|
|
4
|
+
import { S3StorageConfig, StorageController } from "./types.js";
|
|
5
5
|
import { DownloadConfig, StorageListResult, UploadFileProps, UploadFileResult } from "@rebasepro/types";
|
|
6
6
|
/**
|
|
7
7
|
* S3-compatible storage implementation
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache and revalidation headers for served objects.
|
|
3
|
+
*
|
|
4
|
+
* ## Why every byte still goes through the process
|
|
5
|
+
*
|
|
6
|
+
* `routes.ts` deliberately proxies rather than redirecting to a signed URL —
|
|
7
|
+
* mixed content and unreachable VPC endpoints, both documented there. That
|
|
8
|
+
* decision stands. What it cost was caching: a proxied response only caches as
|
|
9
|
+
* well as its headers say, and the local path sent none at all, so every load
|
|
10
|
+
* of every image re-read the file and re-sent the body.
|
|
11
|
+
*
|
|
12
|
+
* This module is the headers. It does not change where bytes come from; it
|
|
13
|
+
* lets the client stop asking for them.
|
|
14
|
+
*
|
|
15
|
+
* ## Why `immutable` is wrong here, and was
|
|
16
|
+
*
|
|
17
|
+
* The remote path sent `public, max-age=3600, immutable`, and the transform
|
|
18
|
+
* paths sent it with `max-age=31536000`. `immutable` is a promise that the body
|
|
19
|
+
* at this URL will never change. A storage key can be overwritten — `putObject`
|
|
20
|
+
* on an existing key is an ordinary operation — so the promise is false for
|
|
21
|
+
* every object this server serves, and the symptom is an upload that replaces a
|
|
22
|
+
* file which then does not visibly change for an hour, or a year.
|
|
23
|
+
*
|
|
24
|
+
* Revalidation replaces it. With a validator the client asks "still this one?"
|
|
25
|
+
* and gets a 304 with no body, which costs a round trip instead of a transfer.
|
|
26
|
+
*
|
|
27
|
+
* ## Why `public` was a leak
|
|
28
|
+
*
|
|
29
|
+
* The same header said `public` for every object, including one that required
|
|
30
|
+
* authentication to fetch. `public` is explicit permission for a *shared* cache
|
|
31
|
+
* — a CDN, a corporate proxy — to store the response and serve it to somebody
|
|
32
|
+
* else. Private objects are now `private`, which is the directive that says a
|
|
33
|
+
* browser may keep it but a shared cache may not.
|
|
34
|
+
*/
|
|
35
|
+
import type { Context } from "hono";
|
|
36
|
+
/**
|
|
37
|
+
* A weak validator built from size and modification time.
|
|
38
|
+
*
|
|
39
|
+
* Weak (`W/`) because it is not a digest of the body: two different bodies of
|
|
40
|
+
* the same length written in the same millisecond would collide. That is the
|
|
41
|
+
* same trade nginx makes for static files, and the alternative — hashing every
|
|
42
|
+
* object on every request — costs more than it saves for content this server is
|
|
43
|
+
* already streaming from somewhere else.
|
|
44
|
+
*/
|
|
45
|
+
export declare function buildEntityTag(size: number, lastModifiedMs: number): string;
|
|
46
|
+
export interface ObjectValidators {
|
|
47
|
+
etag: string;
|
|
48
|
+
/** RFC 9110 date, second-resolution. */
|
|
49
|
+
lastModified: string;
|
|
50
|
+
lastModifiedMs: number;
|
|
51
|
+
}
|
|
52
|
+
export declare function objectValidators(size: number, lastModifiedMs: number): ObjectValidators;
|
|
53
|
+
export interface CacheControlOptions {
|
|
54
|
+
/**
|
|
55
|
+
* Whether a *shared* cache may store this. True only for objects that need
|
|
56
|
+
* no credentials to fetch.
|
|
57
|
+
*/
|
|
58
|
+
isPublic: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* How long a client may reuse the response without asking. Short by
|
|
61
|
+
* default, because the object behind it is mutable.
|
|
62
|
+
*/
|
|
63
|
+
maxAgeSeconds: number;
|
|
64
|
+
/**
|
|
65
|
+
* Public responses only: how long a stale copy may be served while a
|
|
66
|
+
* revalidation happens in the background. Shared caches honour it; it turns
|
|
67
|
+
* the revalidation round trip into something the user does not wait for.
|
|
68
|
+
*/
|
|
69
|
+
staleWhileRevalidateSeconds?: number;
|
|
70
|
+
}
|
|
71
|
+
export declare function cacheControl(options: CacheControlOptions): string;
|
|
72
|
+
/**
|
|
73
|
+
* Whether the request already holds this exact representation.
|
|
74
|
+
*
|
|
75
|
+
* `If-None-Match` wins outright when present: it is an exact validator, whereas
|
|
76
|
+
* `If-Modified-Since` has second resolution and is only consulted in its
|
|
77
|
+
* absence — again the order RFC 9110 requires.
|
|
78
|
+
*/
|
|
79
|
+
export declare function isNotModified(c: Context, validators: ObjectValidators): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Put the validators and the cache policy on a response.
|
|
82
|
+
*
|
|
83
|
+
* Applied to the 304 as well as the 200: a 304 that omits them tells the client
|
|
84
|
+
* nothing about how long the answer holds, so the next load revalidates again
|
|
85
|
+
* immediately and the round trip repeats forever.
|
|
86
|
+
*/
|
|
87
|
+
export declare function applyCacheHeaders(c: Context, validators: ObjectValidators, options: CacheControlOptions): void;
|
package/dist/storage/index.d.ts
CHANGED
|
@@ -11,17 +11,17 @@
|
|
|
11
11
|
* For other providers (Azure Blob, etc.), implement the
|
|
12
12
|
* `StorageController` interface and pass the instance directly to the `storage` config.
|
|
13
13
|
*/
|
|
14
|
-
export * from "./types";
|
|
15
|
-
export { LocalStorageController } from "./LocalStorageController";
|
|
16
|
-
export { S3StorageController } from "./S3StorageController";
|
|
17
|
-
export { GCSStorageController } from "./GCSStorageController";
|
|
18
|
-
export { createStorageRoutes } from "./routes";
|
|
19
|
-
export type { StorageRoutesConfig } from "./routes";
|
|
20
|
-
export * from "./storage-registry";
|
|
21
|
-
export { parseTransformOptions, transformImage, isTransformableImage, TransformCache } from "./image-transform";
|
|
22
|
-
export type { ImageTransformOptions } from "./image-transform";
|
|
23
|
-
export { TusHandler } from "./tus-handler";
|
|
24
|
-
import { BackendStorageConfig, StorageController } from "./types";
|
|
14
|
+
export * from "./types.js";
|
|
15
|
+
export { LocalStorageController } from "./LocalStorageController.js";
|
|
16
|
+
export { S3StorageController } from "./S3StorageController.js";
|
|
17
|
+
export { GCSStorageController } from "./GCSStorageController.js";
|
|
18
|
+
export { createStorageRoutes } from "./routes.js";
|
|
19
|
+
export type { StorageRoutesConfig } from "./routes.js";
|
|
20
|
+
export * from "./storage-registry.js";
|
|
21
|
+
export { parseTransformOptions, transformImage, isTransformableImage, TransformCache } from "./image-transform.js";
|
|
22
|
+
export type { ImageTransformOptions } from "./image-transform.js";
|
|
23
|
+
export { TusHandler } from "./tus-handler.js";
|
|
24
|
+
import { BackendStorageConfig, StorageController } from "./types.js";
|
|
25
25
|
/**
|
|
26
26
|
* Create a storage controller from a config object.
|
|
27
27
|
*
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declarative access control for storage.
|
|
3
|
+
*
|
|
4
|
+
* Storage is not under row-level security, so `storageAuthorize` — a hook, a
|
|
5
|
+
* piece of imperative code — was the whole access-control model. That is the one
|
|
6
|
+
* place the claim "security lives in the database" does not hold, and it shows
|
|
7
|
+
* in the shape of the alternative: without a hook, **any authenticated caller
|
|
8
|
+
* may read, overwrite, delete or list any key they can name**, because storage
|
|
9
|
+
* keys share one flat namespace.
|
|
10
|
+
*
|
|
11
|
+
* A policy list says the same things declaratively, and can be read without
|
|
12
|
+
* running it:
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* storagePolicies: [
|
|
16
|
+
* { path: "public/**", operations: ["read"], allow: "public" },
|
|
17
|
+
* { path: "users/:uid/**", allow: ({ params, user }) => user?.uid === params.uid }
|
|
18
|
+
* ]
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* ## Deny by default, and why that is the whole design
|
|
22
|
+
*
|
|
23
|
+
* A key matched by no policy is refused. That makes every widening an explicit,
|
|
24
|
+
* reviewable line, and it makes a mistake in this module fail *closed* — a
|
|
25
|
+
* pattern that fails to match denies access rather than granting it. Authz code
|
|
26
|
+
* that fails open is worth more to an attacker than the feature is to anyone
|
|
27
|
+
* else, so the bias is deliberate and absolute.
|
|
28
|
+
*
|
|
29
|
+
* ## The hook remains, as an escape hatch and not as a fallback
|
|
30
|
+
*
|
|
31
|
+
* Ownership frequently lives in a row rather than in a key, which no pattern can
|
|
32
|
+
* express. So when policies match nothing, an explicit `storageAuthorize` is
|
|
33
|
+
* consulted before the request is refused. Present, it can widen; absent, the
|
|
34
|
+
* answer is no. Policies never *narrow* what the hook allowed and the hook never
|
|
35
|
+
* overrides a policy denial — each can only say yes, which keeps "who allowed
|
|
36
|
+
* this?" answerable by reading either one alone.
|
|
37
|
+
*/
|
|
38
|
+
import type { StorageAuthorize, StorageAuthorizeContext, StorageOperation } from "@rebasepro/types";
|
|
39
|
+
/** Everything a predicate is told, plus whatever the path captured. */
|
|
40
|
+
export interface StoragePolicyContext extends StorageAuthorizeContext {
|
|
41
|
+
/** Segments captured by `:name` placeholders in the matched path. */
|
|
42
|
+
params: Record<string, string>;
|
|
43
|
+
}
|
|
44
|
+
export type StoragePolicyPredicate = (ctx: StoragePolicyContext) => boolean | Promise<boolean>;
|
|
45
|
+
export interface StoragePolicy {
|
|
46
|
+
/**
|
|
47
|
+
* A key pattern, matched segment by segment against the sanitized key.
|
|
48
|
+
*
|
|
49
|
+
* - a literal segment matches itself
|
|
50
|
+
* - `*` matches exactly one segment
|
|
51
|
+
* - `:name` matches one segment and captures it
|
|
52
|
+
* - `**` matches the rest of the key, including nothing, and is only
|
|
53
|
+
* allowed as the final segment
|
|
54
|
+
*/
|
|
55
|
+
path: string;
|
|
56
|
+
/** Which operations this grants. Defaults to every one of them. */
|
|
57
|
+
operations?: StorageOperation[];
|
|
58
|
+
/**
|
|
59
|
+
* Who it grants to.
|
|
60
|
+
*
|
|
61
|
+
* - `"public"` — anyone, signed in or not
|
|
62
|
+
* - `"authenticated"` — any caller with a uid
|
|
63
|
+
* - a predicate — anything else, given the captured params and the user
|
|
64
|
+
*/
|
|
65
|
+
allow: "public" | "authenticated" | StoragePolicyPredicate;
|
|
66
|
+
}
|
|
67
|
+
export declare class StoragePolicyError extends Error {
|
|
68
|
+
constructor(message: string);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Compile a policy list into a {@link StorageAuthorize}.
|
|
72
|
+
*
|
|
73
|
+
* Compiled once, at boot, so a malformed pattern fails the start rather than the
|
|
74
|
+
* first upload. `fallback` is an explicit `storageAuthorize`, consulted only
|
|
75
|
+
* when no policy matched.
|
|
76
|
+
*/
|
|
77
|
+
export declare function compileStoragePolicies(policies: StoragePolicy[], fallback?: StorageAuthorize): StorageAuthorize;
|
|
78
|
+
/**
|
|
79
|
+
* The access-control function for a configuration, or `undefined` when it
|
|
80
|
+
* declares none.
|
|
81
|
+
*
|
|
82
|
+
* Kept separate from {@link compileStoragePolicies} so `init` has one call to
|
|
83
|
+
* make and one thing to reason about: policies, a hook, both, or neither.
|
|
84
|
+
*/
|
|
85
|
+
export declare function resolveStorageAccessControl(config: {
|
|
86
|
+
storagePolicies?: StoragePolicy[];
|
|
87
|
+
storageAuthorize?: StorageAuthorize;
|
|
88
|
+
}): StorageAuthorize | undefined;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byte-range requests for served objects.
|
|
3
|
+
*
|
|
4
|
+
* Without `Accept-Ranges`, a browser will not offer to seek in an audio or
|
|
5
|
+
* video element served from here: it has no way to ask for the middle of a file,
|
|
6
|
+
* so scrubbing means fetching the whole thing from the start, and on a long
|
|
7
|
+
* recording it means fetching it again for every seek. Safari goes further and
|
|
8
|
+
* refuses to play a `<video>` at all unless the first response is a `206`.
|
|
9
|
+
*
|
|
10
|
+
* So this is not a performance nicety. For media it is the difference between a
|
|
11
|
+
* player that works and one that does not.
|
|
12
|
+
*
|
|
13
|
+
* ## What is implemented, and what is refused
|
|
14
|
+
*
|
|
15
|
+
* A single range — `bytes=0-499`, `bytes=500-`, `bytes=-500`. That is what every
|
|
16
|
+
* browser sends for media playback.
|
|
17
|
+
*
|
|
18
|
+
* Multiple ranges in one request (`bytes=0-99,200-299`) are **not** served.
|
|
19
|
+
* Answering them means composing a `multipart/byteranges` body, and nothing that
|
|
20
|
+
* matters sends them; a server may always answer a range request with the whole
|
|
21
|
+
* `200` instead, which is what happens here. Refusing to guess is better than a
|
|
22
|
+
* half-implemented multipart encoder.
|
|
23
|
+
*
|
|
24
|
+
* An unsatisfiable range — one starting past the end of the object — is a `416`
|
|
25
|
+
* with a `Content-Range: bytes /<size>`, as RFC 9110 requires. Answering `200`
|
|
26
|
+
* there would hand a player the whole file when it asked for a byte that does
|
|
27
|
+
* not exist, and it would never notice.
|
|
28
|
+
*/
|
|
29
|
+
/** A resolved, inclusive byte range within an object of known size. */
|
|
30
|
+
export interface ByteRange {
|
|
31
|
+
start: number;
|
|
32
|
+
/** Inclusive, as the header is. */
|
|
33
|
+
end: number;
|
|
34
|
+
/** `end - start + 1`. */
|
|
35
|
+
length: number;
|
|
36
|
+
}
|
|
37
|
+
export type RangeParse =
|
|
38
|
+
/** No `Range` header, or one this server declines to honour. Serve `200`. */
|
|
39
|
+
{
|
|
40
|
+
kind: "none";
|
|
41
|
+
}
|
|
42
|
+
/** Serve `206` with this range. */
|
|
43
|
+
| {
|
|
44
|
+
kind: "range";
|
|
45
|
+
range: ByteRange;
|
|
46
|
+
}
|
|
47
|
+
/** Serve `416`. The range cannot be satisfied for an object of this size. */
|
|
48
|
+
| {
|
|
49
|
+
kind: "unsatisfiable";
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Parse a `Range` header against an object of `size` bytes.
|
|
53
|
+
*
|
|
54
|
+
* Deliberately conservative: anything malformed, multi-range, or in a unit other
|
|
55
|
+
* than bytes resolves to `none`, which serves the whole object. A range request
|
|
56
|
+
* answered with `200` is always legal; a range answered wrongly is a corrupted
|
|
57
|
+
* download.
|
|
58
|
+
*/
|
|
59
|
+
export declare function parseRange(header: string | undefined, size: number): RangeParse;
|
|
60
|
+
/** The `Content-Range` for a served range. */
|
|
61
|
+
export declare function contentRange(range: ByteRange, size: number): string;
|
|
62
|
+
/** The `Content-Range` for a `416`, which names the size and no range. */
|
|
63
|
+
export declare function unsatisfiableContentRange(size: number): string;
|
package/dist/storage/routes.d.ts
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
* is used.
|
|
8
8
|
*/
|
|
9
9
|
import { Hono } from "hono";
|
|
10
|
-
import { StorageController, type StorageAuthorize, type StorageAuthorizeData } from "./types";
|
|
11
|
-
import { type StorageRegistry } from "./storage-registry";
|
|
10
|
+
import { StorageController, type StorageAuthorize, type StorageAuthorizeData } from "./types.js";
|
|
11
|
+
import { type StorageRegistry } from "./storage-registry.js";
|
|
12
12
|
import { type StorageSourceDefinition, type AuthAdapter } from "@rebasepro/types";
|
|
13
|
-
import { HonoEnv } from "../api/types";
|
|
13
|
+
import { HonoEnv } from "../api/types.js";
|
|
14
14
|
/**
|
|
15
15
|
* Decide what to actually serve for a stored content type.
|
|
16
16
|
*
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - String properties use `storageId` in their config to specify which storage to use
|
|
11
11
|
* - Properties without `storageId` fallback to "(default)"
|
|
12
12
|
*/
|
|
13
|
-
import { StorageController } from "./types";
|
|
13
|
+
import { StorageController } from "./types.js";
|
|
14
14
|
/**
|
|
15
15
|
* The default storage identifier used when:
|
|
16
16
|
* - A single storage controller is provided (not a map)
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* @see https://tus.io/protocols/resumable-upload
|
|
9
9
|
*/
|
|
10
10
|
import type { Context } from "hono";
|
|
11
|
-
import type { StorageController } from "./types";
|
|
12
|
-
import { type StorageRegistry } from "./storage-registry";
|
|
11
|
+
import type { StorageController } from "./types.js";
|
|
12
|
+
import { type StorageRegistry } from "./storage-registry.js";
|
|
13
13
|
/**
|
|
14
14
|
* TUS resumable upload handler.
|
|
15
15
|
*
|