@venizia/ignis 0.4.6 → 0.4.7-1
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.md +1 -4
- package/README.md +2 -2
- package/dist/esm/base/applications/base.d.ts.map +1 -1
- package/dist/esm/base/applications/base.js +19 -15
- package/dist/esm/base/applications/base.js.map +1 -1
- package/dist/esm/base/applications/server.d.ts +14 -9
- package/dist/esm/base/applications/server.d.ts.map +1 -1
- package/dist/esm/base/applications/server.js +36 -29
- package/dist/esm/base/applications/server.js.map +1 -1
- package/dist/esm/base/controllers/grpc/adapter.d.ts.map +1 -1
- package/dist/esm/base/controllers/grpc/adapter.js +5 -1
- package/dist/esm/base/controllers/grpc/adapter.js.map +1 -1
- package/dist/esm/base/middlewares/request-spy/request-spy.middleware.d.ts.map +1 -1
- package/dist/esm/base/middlewares/request-spy/request-spy.middleware.js +9 -3
- package/dist/esm/base/middlewares/request-spy/request-spy.middleware.js.map +1 -1
- package/dist/esm/common/constants.d.ts.map +1 -1
- package/dist/esm/common/constants.js +2 -2
- package/dist/esm/common/constants.js.map +1 -1
- package/dist/esm/components/api-reference/ui/scalar.d.ts.map +1 -1
- package/dist/esm/components/api-reference/ui/scalar.js +2 -1
- package/dist/esm/components/api-reference/ui/scalar.js.map +1 -1
- package/dist/esm/components/api-reference/ui/swagger.d.ts.map +1 -1
- package/dist/esm/components/api-reference/ui/swagger.js +2 -1
- package/dist/esm/components/api-reference/ui/swagger.js.map +1 -1
- package/dist/esm/components/auth/authenticate/component.js +2 -2
- package/dist/esm/components/auth/authenticate/component.js.map +1 -1
- package/dist/esm/components/auth/authenticate/controllers/factory.d.ts +139 -136
- package/dist/esm/components/auth/authenticate/controllers/factory.d.ts.map +1 -1
- package/dist/esm/components/auth/authenticate/controllers/factory.js +175 -172
- package/dist/esm/components/auth/authenticate/controllers/factory.js.map +1 -1
- package/dist/esm/components/auth/authenticate/controllers/jwks/definitions.js +2 -2
- package/dist/esm/components/auth/authenticate/controllers/jwks/definitions.js.map +1 -1
- package/dist/esm/components/auth/authenticate/controllers/service-certs/definitions.js +2 -2
- package/dist/esm/components/auth/authenticate/controllers/service-certs/definitions.js.map +1 -1
- package/dist/esm/components/auth/authenticate/services/bearer/abstract.service.d.ts.map +1 -1
- package/dist/esm/components/auth/authenticate/services/bearer/abstract.service.js +4 -2
- package/dist/esm/components/auth/authenticate/services/bearer/abstract.service.js.map +1 -1
- package/dist/esm/components/auth/authenticate/services/service/signer.service.d.ts.map +1 -1
- package/dist/esm/components/auth/authenticate/services/service/signer.service.js +6 -4
- package/dist/esm/components/auth/authenticate/services/service/signer.service.js.map +1 -1
- package/dist/esm/components/auth/authorize/adapters/base-filtered.js +2 -2
- package/dist/esm/components/auth/authorize/adapters/base-filtered.js.map +1 -1
- package/dist/esm/components/auth/authorize/adapters/custom-grant-expander.d.ts.map +1 -1
- package/dist/esm/components/auth/authorize/adapters/custom-grant-expander.js +2 -2
- package/dist/esm/components/auth/authorize/adapters/custom-grant-expander.js.map +1 -1
- package/dist/esm/components/auth/authorize/adapters/scoped-casbin/adapter.d.ts.map +1 -1
- package/dist/esm/components/auth/authorize/adapters/scoped-casbin/adapter.js +6 -3
- package/dist/esm/components/auth/authorize/adapters/scoped-casbin/adapter.js.map +1 -1
- package/dist/esm/components/auth/authorize/enforcers/casbin-module.d.ts.map +1 -1
- package/dist/esm/components/auth/authorize/enforcers/casbin-module.js +2 -1
- package/dist/esm/components/auth/authorize/enforcers/casbin-module.js.map +1 -1
- package/dist/esm/components/auth/authorize/enforcers/casbin.enforcer.d.ts.map +1 -1
- package/dist/esm/components/auth/authorize/enforcers/casbin.enforcer.js +9 -3
- package/dist/esm/components/auth/authorize/enforcers/casbin.enforcer.js.map +1 -1
- package/dist/esm/components/auth/models/entities/columns.d.ts +99 -0
- package/dist/esm/components/auth/models/entities/columns.d.ts.map +1 -0
- package/dist/esm/components/auth/models/entities/columns.js +133 -0
- package/dist/esm/components/auth/models/entities/columns.js.map +1 -0
- package/dist/esm/components/auth/models/entities/index.d.ts +1 -2
- package/dist/esm/components/auth/models/entities/index.d.ts.map +1 -1
- package/dist/esm/components/auth/models/entities/index.js +1 -2
- package/dist/esm/components/auth/models/entities/index.js.map +1 -1
- package/dist/esm/components/auth/models/entities/permission.model.d.ts +1 -12
- package/dist/esm/components/auth/models/entities/permission.model.d.ts.map +1 -1
- package/dist/esm/components/auth/models/entities/permission.model.js +1 -36
- package/dist/esm/components/auth/models/entities/permission.model.js.map +1 -1
- package/dist/esm/components/auth/models/entities/policy-definition.model.d.ts +1 -49
- package/dist/esm/components/auth/models/entities/policy-definition.model.d.ts.map +1 -1
- package/dist/esm/components/auth/models/entities/policy-definition.model.js +1 -69
- package/dist/esm/components/auth/models/entities/policy-definition.model.js.map +1 -1
- package/dist/esm/components/controller/grpc/grpc.component.js +2 -2
- package/dist/esm/components/controller/grpc/grpc.component.js.map +1 -1
- package/dist/esm/components/health-check/component.d.ts.map +1 -1
- package/dist/esm/components/health-check/component.js +5 -3
- package/dist/esm/components/health-check/component.js.map +1 -1
- package/dist/esm/components/health-check/controller.js +5 -5
- package/dist/esm/components/health-check/controller.js.map +1 -1
- package/dist/esm/components/index.d.ts +0 -1
- package/dist/esm/components/index.d.ts.map +1 -1
- package/dist/esm/components/index.js +0 -1
- package/dist/esm/components/index.js.map +1 -1
- package/dist/esm/components/mail/helpers/executors/bull-mq-executor.helper.d.ts.map +1 -1
- package/dist/esm/components/mail/helpers/executors/bull-mq-executor.helper.js +2 -1
- package/dist/esm/components/mail/helpers/executors/bull-mq-executor.helper.js.map +1 -1
- package/dist/esm/components/mail/helpers/transporters/amazon-ses-transporter.helper.d.ts.map +1 -1
- package/dist/esm/components/mail/helpers/transporters/amazon-ses-transporter.helper.js +13 -9
- package/dist/esm/components/mail/helpers/transporters/amazon-ses-transporter.helper.js.map +1 -1
- package/dist/esm/components/mail/helpers/transporters/mailgun-transporter.helper.d.ts.map +1 -1
- package/dist/esm/components/mail/helpers/transporters/mailgun-transporter.helper.js +5 -3
- package/dist/esm/components/mail/helpers/transporters/mailgun-transporter.helper.js.map +1 -1
- package/dist/esm/components/mail/helpers/transporters/nodemail-transporter.helper.d.ts.map +1 -1
- package/dist/esm/components/mail/helpers/transporters/nodemail-transporter.helper.js +9 -7
- package/dist/esm/components/mail/helpers/transporters/nodemail-transporter.helper.js.map +1 -1
- package/dist/esm/components/mail/services/generators/verification-data.d.ts.map +1 -1
- package/dist/esm/components/mail/services/generators/verification-data.js +7 -3
- package/dist/esm/components/mail/services/generators/verification-data.js.map +1 -1
- package/dist/esm/components/mail/services/mail.service.d.ts.map +1 -1
- package/dist/esm/components/mail/services/mail.service.js +12 -9
- package/dist/esm/components/mail/services/mail.service.js.map +1 -1
- package/dist/esm/components/mail/utilities/address.utility.d.ts +12 -8
- package/dist/esm/components/mail/utilities/address.utility.d.ts.map +1 -1
- package/dist/esm/components/mail/utilities/address.utility.js +30 -27
- package/dist/esm/components/mail/utilities/address.utility.js.map +1 -1
- package/dist/esm/components/mail/utilities/attachment.utility.d.ts +31 -29
- package/dist/esm/components/mail/utilities/attachment.utility.d.ts.map +1 -1
- package/dist/esm/components/mail/utilities/attachment.utility.js +94 -86
- package/dist/esm/components/mail/utilities/attachment.utility.js.map +1 -1
- package/dist/esm/components/mail/utilities/body.utility.d.ts +6 -4
- package/dist/esm/components/mail/utilities/body.utility.d.ts.map +1 -1
- package/dist/esm/components/mail/utilities/body.utility.js +14 -12
- package/dist/esm/components/mail/utilities/body.utility.js.map +1 -1
- package/dist/esm/components/mail/utilities/mime.utility.d.ts +23 -17
- package/dist/esm/components/mail/utilities/mime.utility.d.ts.map +1 -1
- package/dist/esm/components/mail/utilities/mime.utility.js +109 -98
- package/dist/esm/components/mail/utilities/mime.utility.js.map +1 -1
- package/dist/esm/components/mail/utilities/verification.utility.d.ts +8 -2
- package/dist/esm/components/mail/utilities/verification.utility.d.ts.map +1 -1
- package/dist/esm/components/mail/utilities/verification.utility.js +7 -5
- package/dist/esm/components/mail/utilities/verification.utility.js.map +1 -1
- package/dist/esm/components/socket-io/component.js +3 -3
- package/dist/esm/components/socket-io/component.js.map +1 -1
- package/dist/esm/components/socket-io/handlers/bun.handler.d.ts +13 -11
- package/dist/esm/components/socket-io/handlers/bun.handler.d.ts.map +1 -1
- package/dist/esm/components/socket-io/handlers/bun.handler.js +32 -30
- package/dist/esm/components/socket-io/handlers/bun.handler.js.map +1 -1
- package/dist/esm/components/static-asset/common/commit-token.d.ts +21 -16
- package/dist/esm/components/static-asset/common/commit-token.d.ts.map +1 -1
- package/dist/esm/components/static-asset/common/commit-token.js +35 -28
- package/dist/esm/components/static-asset/common/commit-token.js.map +1 -1
- package/dist/esm/components/static-asset/common/constants.d.ts +0 -2
- package/dist/esm/components/static-asset/common/constants.d.ts.map +1 -1
- package/dist/esm/components/static-asset/common/constants.js +1 -3
- package/dist/esm/components/static-asset/common/constants.js.map +1 -1
- package/dist/esm/components/static-asset/common/types.d.ts +0 -4
- package/dist/esm/components/static-asset/common/types.d.ts.map +1 -1
- package/dist/esm/components/static-asset/common/types.js.map +1 -1
- package/dist/esm/components/static-asset/component.js +2 -2
- package/dist/esm/components/static-asset/component.js.map +1 -1
- package/dist/esm/components/static-asset/controller/base.definition.d.ts +6 -6
- package/dist/esm/components/static-asset/controller/base.definition.d.ts.map +1 -1
- package/dist/esm/components/static-asset/controller/base.definition.js +224 -224
- package/dist/esm/components/static-asset/controller/base.definition.js.map +1 -1
- package/dist/esm/components/static-asset/controller/factory.d.ts +23 -23
- package/dist/esm/components/static-asset/controller/factory.d.ts.map +1 -1
- package/dist/esm/components/static-asset/controller/factory.js +104 -74
- package/dist/esm/components/static-asset/controller/factory.js.map +1 -1
- package/dist/esm/components/static-asset/controller/key-scope.d.ts +28 -26
- package/dist/esm/components/static-asset/controller/key-scope.d.ts.map +1 -1
- package/dist/esm/components/static-asset/controller/key-scope.js +34 -30
- package/dist/esm/components/static-asset/controller/key-scope.js.map +1 -1
- package/dist/esm/components/static-asset/controller/meta-link.d.ts +37 -33
- package/dist/esm/components/static-asset/controller/meta-link.d.ts.map +1 -1
- package/dist/esm/components/static-asset/controller/meta-link.js +86 -84
- package/dist/esm/components/static-asset/controller/meta-link.js.map +1 -1
- package/dist/esm/components/static-asset/controller/route-options.d.ts +18 -16
- package/dist/esm/components/static-asset/controller/route-options.d.ts.map +1 -1
- package/dist/esm/components/static-asset/controller/route-options.js +28 -26
- package/dist/esm/components/static-asset/controller/route-options.js.map +1 -1
- package/dist/esm/components/static-asset/models/base.model.js +3 -3
- package/dist/esm/components/static-asset/models/base.model.js.map +1 -1
- package/dist/esm/components/websocket/component.js +2 -2
- package/dist/esm/components/websocket/component.js.map +1 -1
- package/dist/esm/components/websocket/handlers/bun.handler.d.ts +6 -4
- package/dist/esm/components/websocket/handlers/bun.handler.d.ts.map +1 -1
- package/dist/esm/components/websocket/handlers/bun.handler.js +21 -19
- package/dist/esm/components/websocket/handlers/bun.handler.js.map +1 -1
- package/dist/esm/testing/assert-application-boots.d.ts +6 -1
- package/dist/esm/testing/assert-application-boots.d.ts.map +1 -1
- package/dist/esm/testing/assert-application-boots.js +139 -129
- package/dist/esm/testing/assert-application-boots.js.map +1 -1
- package/dist/esm/utilities/drizzle-result.utility.d.ts +6 -8
- package/dist/esm/utilities/drizzle-result.utility.d.ts.map +1 -1
- package/dist/esm/utilities/drizzle-result.utility.js +23 -49
- package/dist/esm/utilities/drizzle-result.utility.js.map +1 -1
- package/dist/esm/utilities/network.utility.d.ts.map +1 -1
- package/dist/esm/utilities/network.utility.js +1 -1
- package/dist/esm/utilities/network.utility.js.map +1 -1
- package/dist/presets/app/files/src/boot.test.ts +2 -2
- package/dist/presets/app/files/src/controllers/hello.controller.ts +2 -2
- package/dist/presets/app/preset.json +4 -4
- package/dist/presets/lib/preset.json +4 -4
- package/dist/presets/shared/files/.configs/formatters/.ignore +4 -0
- package/dist/presets/shared/files/.configs/lints/.ignore +4 -0
- package/dist/presets/shared/files/.configs/lints/eslint.config.mjs +4 -0
- package/dist/presets/shared/files/.configs/lints/oxlint.config.mts +4 -0
- package/dist/presets/shared/files/README.md +15 -0
- package/dist/presets/shared/files/src/index.test.ts +8 -0
- package/dist/presets/shared/files/src/index.ts +8 -0
- package/dist/presets/shared/files/tsconfig.json +20 -0
- package/dist/presets/shared/preset.json +35 -0
- package/package.json +11 -11
- package/dist/esm/components/auth/models/entities/role.model.d.ts +0 -10
- package/dist/esm/components/auth/models/entities/role.model.d.ts.map +0 -1
- package/dist/esm/components/auth/models/entities/role.model.js +0 -15
- package/dist/esm/components/auth/models/entities/role.model.js.map +0 -1
- package/dist/esm/components/auth/models/entities/user.model.d.ts +0 -28
- package/dist/esm/components/auth/models/entities/user.model.d.ts.map +0 -1
- package/dist/esm/components/auth/models/entities/user.model.js +0 -17
- package/dist/esm/components/auth/models/entities/user.model.js.map +0 -1
- package/dist/esm/components/controller/index.d.ts +0 -2
- package/dist/esm/components/controller/index.d.ts.map +0 -1
- package/dist/esm/components/controller/index.js +0 -7
- package/dist/esm/components/controller/index.js.map +0 -1
|
@@ -24,31 +24,31 @@ export interface IAssetControllerOptions {
|
|
|
24
24
|
/** The upload labels, read off the multipart form. Every value arrives as text, so `sequence` is the one that needs converting. */
|
|
25
25
|
/** One list: the reader below and the stale-caller warning must agree. */
|
|
26
26
|
declare const UPLOAD_LABEL_NAMES: readonly ["principalType", "principalId", "variant", "sequence", "folderPath"];
|
|
27
|
-
/** Names any label a caller put in the query - where the upload routes refuse it. */
|
|
28
|
-
export declare const findLabelsInQuery: (opts: {
|
|
29
|
-
query: Record<string, string>;
|
|
30
|
-
names?: ReadonlyArray<(typeof UPLOAD_LABEL_NAMES)[number]>;
|
|
31
|
-
}) => string[];
|
|
32
|
-
/** The URL of one object, in the shape its controller serves: no `/buckets/<name>` with a configured bucket, and a raw path with `rawObjectPath`. */
|
|
33
|
-
export declare const buildObjectLink: (opts: IObjectLocation & {
|
|
34
|
-
basePath: string;
|
|
35
|
-
hasConfiguredBucket?: boolean;
|
|
36
|
-
rawObjectPath?: boolean;
|
|
37
|
-
}) => string;
|
|
38
|
-
/**
|
|
39
|
-
* The served type comes from the object NAME, never the backend or the uploader: a renderable type on
|
|
40
|
-
* the API origin is stored XSS. Exported so a hand-written route makes the same decision - the
|
|
41
|
-
* backend's own content-type is dropped by `WHITELIST_HEADERS`.
|
|
42
|
-
*/
|
|
43
|
-
export declare const resolveServedContentType: (opts: {
|
|
44
|
-
helper: IStorageHelper;
|
|
45
|
-
object: IObjectRef;
|
|
46
|
-
}) => {
|
|
47
|
-
contentType: string;
|
|
48
|
-
isRenderable: boolean;
|
|
49
|
-
};
|
|
50
27
|
export declare class AssetControllerFactory extends BaseHelper {
|
|
51
28
|
constructor();
|
|
29
|
+
/** Names any label a caller put in the query - where the upload routes refuse it. */
|
|
30
|
+
static findLabelsInQuery(opts: {
|
|
31
|
+
query: Record<string, string>;
|
|
32
|
+
names?: ReadonlyArray<(typeof UPLOAD_LABEL_NAMES)[number]>;
|
|
33
|
+
}): string[];
|
|
34
|
+
/** The URL of one object, in the shape its controller serves: no `/buckets/<name>` with a configured bucket, and a raw path with `rawObjectPath`. */
|
|
35
|
+
static buildObjectLink(opts: IObjectLocation & {
|
|
36
|
+
basePath: string;
|
|
37
|
+
hasConfiguredBucket?: boolean;
|
|
38
|
+
rawObjectPath?: boolean;
|
|
39
|
+
}): string;
|
|
40
|
+
/**
|
|
41
|
+
* The served type comes from the object NAME, never the backend or the uploader: a renderable type on
|
|
42
|
+
* the API origin is stored XSS. Public so a hand-written route makes the same decision - the
|
|
43
|
+
* backend's own content-type is dropped by `WHITELIST_HEADERS`.
|
|
44
|
+
*/
|
|
45
|
+
static resolveServedContentType(opts: {
|
|
46
|
+
helper: IStorageHelper;
|
|
47
|
+
object: IObjectRef;
|
|
48
|
+
}): {
|
|
49
|
+
contentType: string;
|
|
50
|
+
isRenderable: boolean;
|
|
51
|
+
};
|
|
52
52
|
static defineAssetController(opts: IAssetControllerOptions): {
|
|
53
53
|
new (): {
|
|
54
54
|
/** Clears the multipart spool files written by `parseMultipartBody({ storage: 'disk' })`. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../../../src/components/static-asset/controller/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAE5E,OAAO,
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../../../src/components/static-asset/controller/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAE5E,OAAO,EAIL,KAAK,eAAe,EAEpB,KAAK,UAAU,EACf,KAAK,cAAc,EAKpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAyB,KAAK,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC3F,OAAO,KAAK,EAAE,OAAO,EAAyB,MAAM,+BAA+B,CAAC;AACpF,OAAO,EAAE,UAAU,EAAwB,MAAM,6BAA6B,CAAC;AAC/E,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AAEhC,OAAO,EAIL,KAAK,kBAAkB,EAEvB,KAAK,eAAe,EAKpB,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,6BAA6B,EAClC,KAAK,uBAAuB,EAG7B,MAAM,WAAW,CAAC;AAOnB,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,6BAA6B,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAChE,OAAO,EAAE,uBAAuB,CAAC;IACjC,MAAM,EAAE,cAAc,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iRAAiR;IACjR,QAAQ,CAAC,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,wBAAwB,CAAC;IAEnC,qHAAqH;IACrH,iBAAiB,CAAC,EAAE,mBAAmB,CAAC;IAExC,oGAAoG;IACpG,4IAA4I;IAC5I,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,iBAAiB,CAAC,EAAE,kBAAkB,CAAC;CACxC;AAED,6OAA6O;AAC7O,mIAAmI;AACnI,0EAA0E;AAC1E,QAAA,MAAM,kBAAkB,gFAMd,CAAC;AAuIX,qBAAa,sBAAuB,SAAQ,UAAU;;IAKpD,qFAAqF;IACrF,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE;QAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC9B,KAAK,CAAC,EAAE,aAAa,CAAC,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;KAC5D,GAAG,MAAM,EAAE;IAIZ,qJAAqJ;IACrJ,MAAM,CAAC,eAAe,CACpB,IAAI,EAAE,eAAe,GAAG;QACtB,QAAQ,EAAE,MAAM,CAAC;QACjB,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;KACzB,GACA,MAAM;IAUT;;;;OAIG;IACH,MAAM,CAAC,wBAAwB,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,cAAc,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAE,GAAG;QACrF,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,OAAO,CAAC;KACvB;IAeD,MAAM,CAAC,qBAAqB,CAAC,IAAI,EAAE,uBAAuB;;YAwDtD,6FAA6F;2CAC9D;gBAAE,KAAK,EAAE,MAAM,EAAE,CAAA;aAAE,GAAG,IAAI;uBAYrC,cAAc,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA5RzC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmoCL"}
|
|
@@ -9,16 +9,16 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
9
9
|
};
|
|
10
10
|
import { BaseRestController } from '../../../base/controllers/index.js';
|
|
11
11
|
import { controller as controllerDecorator } from '../../../base/metadata/index.js';
|
|
12
|
-
import { BaseStorageHelper,
|
|
13
|
-
import { HTTP,
|
|
12
|
+
import { BaseStorageHelper, RequestUtility, StorageUtility, } from '@venizia/ignis-helpers';
|
|
13
|
+
import { HTTP, ResolverUtility } from '@venizia/ignis-helpers/common';
|
|
14
14
|
import { BaseHelper, getError, UuidHelper } from '@venizia/ignis-helpers/core';
|
|
15
15
|
import { readFileSync, rmSync } from 'node:fs';
|
|
16
16
|
import { RENDERABLE_CONTENT_TYPES, StaticAssetErrors, DEFAULT_PENDING_PREFIX, META_LINK_CREATE_FAILED, WHITELIST_HEADERS, } from '../common/index.js';
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
17
|
+
import { AssetCommitToken, MetaLinkRecreateActions } from '../common/index.js';
|
|
18
|
+
import { AssetDefinitionBuilder } from './base.definition.js';
|
|
19
|
+
import { AssetKeyScope } from './key-scope.js';
|
|
20
|
+
import { AssetMetaLink } from './meta-link.js';
|
|
21
|
+
import { AssetRouteOptions } from './route-options.js';
|
|
22
22
|
/** Hono ALREADY percent-decodes path params - a second decodeURIComponent throws on `report_100%.pdf` and turns `a%2Fb.png` into a DIFFERENT object; `isValidName`/`isValidPath` still run on this value, so traversal is still rejected. */
|
|
23
23
|
/** The upload labels, read off the multipart form. Every value arrives as text, so `sequence` is the one that needs converting. */
|
|
24
24
|
/** One list: the reader below and the stale-caller warning must agree. */
|
|
@@ -29,11 +29,11 @@ const UPLOAD_LABEL_NAMES = [
|
|
|
29
29
|
'sequence',
|
|
30
30
|
'folderPath',
|
|
31
31
|
];
|
|
32
|
-
/**
|
|
33
|
-
|
|
32
|
+
/** The body of `AssetControllerFactory.findLabelsInQuery`, callable from the helpers above the class. */
|
|
33
|
+
const listLabelsInQuery = (opts) => (opts.names ?? UPLOAD_LABEL_NAMES).filter((name) => opts.query[name] !== undefined);
|
|
34
34
|
/** Refused before the body is read: a route that ignored them would store an unlabelled row. */
|
|
35
35
|
const refuseLabelsInQuery = (opts) => {
|
|
36
|
-
const names =
|
|
36
|
+
const names = listLabelsInQuery(opts);
|
|
37
37
|
if (names.length > 0) {
|
|
38
38
|
throw getError({
|
|
39
39
|
error: StaticAssetErrors.LABELS_IN_QUERY,
|
|
@@ -70,15 +70,7 @@ const resolveBucket = async (opts) => {
|
|
|
70
70
|
if (configured === undefined) {
|
|
71
71
|
return param ?? '';
|
|
72
72
|
}
|
|
73
|
-
return resolveValueAsync({ value: configured });
|
|
74
|
-
};
|
|
75
|
-
/** The URL of one object, in the shape its controller serves: no `/buckets/<name>` with a configured bucket, and a raw path with `rawObjectPath`. */
|
|
76
|
-
export const buildObjectLink = (opts) => {
|
|
77
|
-
const { basePath, bucket, object } = opts;
|
|
78
|
-
const { hasConfiguredBucket = false, rawObjectPath = false } = opts;
|
|
79
|
-
const bucketSegment = hasConfiguredBucket ? '' : `/buckets/${bucket.name}`;
|
|
80
|
-
const objectSegment = rawObjectPath ? object.key : encodeObjectPath(object.key);
|
|
81
|
-
return `${basePath}${bucketSegment}/objects/${objectSegment}`;
|
|
73
|
+
return ResolverUtility.resolveValueAsync({ value: configured });
|
|
82
74
|
};
|
|
83
75
|
/** Mirrors `BaseStorageHelper.normalizeObjectName`, which is protected: `resolveObjectName` is offered the very name the helper would otherwise have written. */
|
|
84
76
|
const defaultObjectName = ({ file }) => {
|
|
@@ -89,19 +81,6 @@ const defaultObjectName = ({ file }) => {
|
|
|
89
81
|
}
|
|
90
82
|
return `${folderPath.toLowerCase().replace(/ /g, '_')}/${normalizedFileName}`;
|
|
91
83
|
};
|
|
92
|
-
/**
|
|
93
|
-
* The served type comes from the object NAME, never the backend or the uploader: a renderable type on
|
|
94
|
-
* the API origin is stored XSS. Exported so a hand-written route makes the same decision - the
|
|
95
|
-
* backend's own content-type is dropped by `WHITELIST_HEADERS`.
|
|
96
|
-
*/
|
|
97
|
-
export const resolveServedContentType = (opts) => {
|
|
98
|
-
const { helper, object } = opts;
|
|
99
|
-
const candidate = helper.getMimeType({ filename: object.key }).toLowerCase().split(';')[0].trim();
|
|
100
|
-
if (!RENDERABLE_CONTENT_TYPES.has(candidate)) {
|
|
101
|
-
return { contentType: HTTP.HeaderValues.APPLICATION_OCTET_STREAM, isRenderable: false };
|
|
102
|
-
}
|
|
103
|
-
return { contentType: candidate, isRenderable: true };
|
|
104
|
-
};
|
|
105
84
|
/**
|
|
106
85
|
* Reads one `Range` header. Only a single byte range is honoured - multipart ranges need a multipart
|
|
107
86
|
* body no browser asks for here. An unsatisfiable or malformed range returns `null`, and the caller
|
|
@@ -145,6 +124,35 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
145
124
|
constructor() {
|
|
146
125
|
super({ scope: AssetControllerFactory.name });
|
|
147
126
|
}
|
|
127
|
+
/** Names any label a caller put in the query - where the upload routes refuse it. */
|
|
128
|
+
static findLabelsInQuery(opts) {
|
|
129
|
+
return listLabelsInQuery(opts);
|
|
130
|
+
}
|
|
131
|
+
/** The URL of one object, in the shape its controller serves: no `/buckets/<name>` with a configured bucket, and a raw path with `rawObjectPath`. */
|
|
132
|
+
static buildObjectLink(opts) {
|
|
133
|
+
const { basePath, bucket, object } = opts;
|
|
134
|
+
const { hasConfiguredBucket = false, rawObjectPath = false } = opts;
|
|
135
|
+
const bucketSegment = hasConfiguredBucket ? '' : `/buckets/${bucket.name}`;
|
|
136
|
+
const objectSegment = rawObjectPath ? object.key : encodeObjectPath(object.key);
|
|
137
|
+
return `${basePath}${bucketSegment}/objects/${objectSegment}`;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* The served type comes from the object NAME, never the backend or the uploader: a renderable type on
|
|
141
|
+
* the API origin is stored XSS. Public so a hand-written route makes the same decision - the
|
|
142
|
+
* backend's own content-type is dropped by `WHITELIST_HEADERS`.
|
|
143
|
+
*/
|
|
144
|
+
static resolveServedContentType(opts) {
|
|
145
|
+
const { helper, object } = opts;
|
|
146
|
+
const candidate = helper
|
|
147
|
+
.getMimeType({ filename: object.key })
|
|
148
|
+
.toLowerCase()
|
|
149
|
+
.split(';')[0]
|
|
150
|
+
.trim();
|
|
151
|
+
if (!RENDERABLE_CONTENT_TYPES.has(candidate)) {
|
|
152
|
+
return { contentType: HTTP.HeaderValues.APPLICATION_OCTET_STREAM, isRenderable: false };
|
|
153
|
+
}
|
|
154
|
+
return { contentType: candidate, isRenderable: true };
|
|
155
|
+
}
|
|
148
156
|
static defineAssetController(opts) {
|
|
149
157
|
const { controller, helper, options, useMetaLink, metaLink, storage } = opts;
|
|
150
158
|
const { resolveObjectName, defineRoutesBefore, defineExtraRoutes } = opts;
|
|
@@ -161,18 +169,18 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
161
169
|
}
|
|
162
170
|
const scope = controller.keyPrefix === undefined
|
|
163
171
|
? undefined
|
|
164
|
-
:
|
|
172
|
+
: AssetKeyScope.normalizePrefix({ keyPrefix: controller.keyPrefix, helper, scope: name });
|
|
165
173
|
const keyPrefix = scope?.keyPrefix;
|
|
166
174
|
// `maxFolderDepth` counts the caller's folders; the scope's own are configuration, not input.
|
|
167
175
|
const objectKeyMaxDepth = maxFolderDepth + (scope?.depth ?? 0);
|
|
168
176
|
// The component's own name under a scope: the original name must stay one segment, as without one.
|
|
169
177
|
const isScopedDefaultNaming = keyPrefix !== undefined && !resolveObjectName && !options?.normalizeNameFn;
|
|
170
|
-
const definitions =
|
|
178
|
+
const definitions = AssetDefinitionBuilder.build({ hasConfiguredBucket, rawObjectPath });
|
|
171
179
|
// The mount path may be declared with or without a leading slash; a link must carry exactly one.
|
|
172
180
|
const normalizedBasePath = basePath.startsWith('/') ? basePath : `/${basePath}`;
|
|
173
181
|
/** Only when the URL shape deviates: with neither option the storage helper's own link is left untouched. */
|
|
174
182
|
const shapedLinkFn = hasConfiguredBucket || rawObjectPath
|
|
175
|
-
? (linkOptions) => buildObjectLink({
|
|
183
|
+
? (linkOptions) => AssetControllerFactory.buildObjectLink({
|
|
176
184
|
basePath: normalizedBasePath,
|
|
177
185
|
bucket: linkOptions.bucket,
|
|
178
186
|
object: linkOptions.object,
|
|
@@ -208,7 +216,7 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
208
216
|
// A single-bucket application has no reason to expose bucket creation or deletion, so the
|
|
209
217
|
// four bucket-management routes are not registered once `bucket` is configured.
|
|
210
218
|
if (!hasConfiguredBucket) {
|
|
211
|
-
const getBucketsRoute =
|
|
219
|
+
const getBucketsRoute = AssetRouteOptions.readOverride({ route: routes?.getBuckets });
|
|
212
220
|
if (getBucketsRoute.isEnabled) {
|
|
213
221
|
this.bindRoute({
|
|
214
222
|
configs: { ...definitions.GET_BUCKETS, ...getBucketsRoute.override },
|
|
@@ -219,7 +227,9 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
219
227
|
},
|
|
220
228
|
});
|
|
221
229
|
}
|
|
222
|
-
const getBucketByNameRoute =
|
|
230
|
+
const getBucketByNameRoute = AssetRouteOptions.readOverride({
|
|
231
|
+
route: routes?.getBucketByName,
|
|
232
|
+
});
|
|
223
233
|
if (getBucketByNameRoute.isEnabled) {
|
|
224
234
|
this.bindRoute({
|
|
225
235
|
configs: { ...definitions.GET_BUCKET_BY_NAME, ...getBucketByNameRoute.override },
|
|
@@ -238,7 +248,7 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
238
248
|
},
|
|
239
249
|
});
|
|
240
250
|
}
|
|
241
|
-
const createBucketRoute =
|
|
251
|
+
const createBucketRoute = AssetRouteOptions.readOverride({ route: routes?.createBucket });
|
|
242
252
|
if (createBucketRoute.isEnabled) {
|
|
243
253
|
this.bindRoute({
|
|
244
254
|
configs: { ...definitions.CREATE_BUCKET, ...createBucketRoute.override },
|
|
@@ -257,7 +267,7 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
257
267
|
},
|
|
258
268
|
});
|
|
259
269
|
}
|
|
260
|
-
const deleteBucketRoute =
|
|
270
|
+
const deleteBucketRoute = AssetRouteOptions.readOverride({ route: routes?.deleteBucket });
|
|
261
271
|
if (deleteBucketRoute.isEnabled) {
|
|
262
272
|
this.bindRoute({
|
|
263
273
|
configs: { ...definitions.DELETE_BUCKET, ...deleteBucketRoute.override },
|
|
@@ -279,7 +289,9 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
279
289
|
});
|
|
280
290
|
}
|
|
281
291
|
}
|
|
282
|
-
const getObjectByNameRoute =
|
|
292
|
+
const getObjectByNameRoute = AssetRouteOptions.readOverride({
|
|
293
|
+
route: routes?.getObjectByName,
|
|
294
|
+
});
|
|
283
295
|
if (getObjectByNameRoute.isEnabled) {
|
|
284
296
|
this.bindRoute({
|
|
285
297
|
configs: { ...definitions.GET_OBJECT_BY_NAME, ...getObjectByNameRoute.override },
|
|
@@ -301,14 +313,17 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
301
313
|
throw getError({ error: StaticAssetErrors.OBJECT_NAME_INVALID });
|
|
302
314
|
}
|
|
303
315
|
// Before any storage call: a key outside the scope must not even be probed.
|
|
304
|
-
|
|
316
|
+
AssetKeyScope.assertInScope({ key: objectName, keyPrefix });
|
|
305
317
|
const fileStat = await helper.getStat({
|
|
306
318
|
bucket: { name: bucketName },
|
|
307
319
|
object: { key: objectName },
|
|
308
320
|
});
|
|
309
321
|
const { size, metadata } = fileStat;
|
|
310
322
|
applyMetadataHeaders({ ctx, metadata });
|
|
311
|
-
const served = resolveServedContentType({
|
|
323
|
+
const served = AssetControllerFactory.resolveServedContentType({
|
|
324
|
+
helper,
|
|
325
|
+
object: { key: objectName },
|
|
326
|
+
});
|
|
312
327
|
ctx.header(HTTP.Headers.CONTENT_TYPE, served.contentType);
|
|
313
328
|
ctx.header('x-content-type-options', 'nosniff');
|
|
314
329
|
// Sandboxed even when renderable, so an unforeseen renderable type cannot reach this origin.
|
|
@@ -318,7 +333,10 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
318
333
|
// A type outside the allow-list downloads instead of rendering; that is the XSS boundary.
|
|
319
334
|
if (!served.isRenderable) {
|
|
320
335
|
const inlineName = objectName.split('/').pop() ?? objectName;
|
|
321
|
-
ctx.header(HTTP.Headers.CONTENT_DISPOSITION,
|
|
336
|
+
ctx.header(HTTP.Headers.CONTENT_DISPOSITION, RequestUtility.buildContentDispositionHeader({
|
|
337
|
+
filename: inlineName,
|
|
338
|
+
type: 'attachment',
|
|
339
|
+
}));
|
|
322
340
|
}
|
|
323
341
|
const range = readByteRange({ header: ctx.req.header('range'), size });
|
|
324
342
|
if (range) {
|
|
@@ -341,7 +359,7 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
341
359
|
},
|
|
342
360
|
});
|
|
343
361
|
}
|
|
344
|
-
const downloadObjectByNameRoute =
|
|
362
|
+
const downloadObjectByNameRoute = AssetRouteOptions.readOverride({
|
|
345
363
|
route: routes?.downloadObjectByName,
|
|
346
364
|
});
|
|
347
365
|
if (downloadObjectByNameRoute.isEnabled) {
|
|
@@ -368,7 +386,7 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
368
386
|
throw getError({ error: StaticAssetErrors.OBJECT_NAME_INVALID });
|
|
369
387
|
}
|
|
370
388
|
// Before any storage call: a key outside the scope must not even be probed.
|
|
371
|
-
|
|
389
|
+
AssetKeyScope.assertInScope({ key: objectName, keyPrefix });
|
|
372
390
|
const fileStat = await helper.getStat({
|
|
373
391
|
bucket: { name: bucketName },
|
|
374
392
|
object: { key: objectName },
|
|
@@ -376,11 +394,17 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
376
394
|
const { size, metadata } = fileStat;
|
|
377
395
|
applyMetadataHeaders({ ctx, metadata });
|
|
378
396
|
// Download always attaches, so the served type only has to be honest, never renderable.
|
|
379
|
-
const served = resolveServedContentType({
|
|
397
|
+
const served = AssetControllerFactory.resolveServedContentType({
|
|
398
|
+
helper,
|
|
399
|
+
object: { key: objectName },
|
|
400
|
+
});
|
|
380
401
|
ctx.header(HTTP.Headers.CONTENT_TYPE, served.contentType);
|
|
381
402
|
ctx.header(HTTP.Headers.CONTENT_LENGTH, size.toString());
|
|
382
403
|
const fileName = objectName.split('/').pop() ?? objectName;
|
|
383
|
-
ctx.header(HTTP.Headers.CONTENT_DISPOSITION,
|
|
404
|
+
ctx.header(HTTP.Headers.CONTENT_DISPOSITION, RequestUtility.buildContentDispositionHeader({
|
|
405
|
+
filename: fileName,
|
|
406
|
+
type: 'attachment',
|
|
407
|
+
}));
|
|
384
408
|
ctx.header('x-content-type-options', 'nosniff');
|
|
385
409
|
ctx.header(HTTP.Headers.CONTENT_SECURITY_POLICY, 'sandbox');
|
|
386
410
|
const stream = await helper.getObjectStream({
|
|
@@ -394,11 +418,11 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
394
418
|
},
|
|
395
419
|
});
|
|
396
420
|
}
|
|
397
|
-
const uploadRoute =
|
|
421
|
+
const uploadRoute = AssetRouteOptions.readOverride({ route: routes?.upload });
|
|
398
422
|
if (uploadRoute.isEnabled) {
|
|
399
423
|
const uploadMiddleware = maxBytes === undefined
|
|
400
424
|
? uploadRoute.override.middleware
|
|
401
|
-
:
|
|
425
|
+
: AssetRouteOptions.appendLengthGuard({
|
|
402
426
|
middleware: uploadRoute.override.middleware,
|
|
403
427
|
maxBytes,
|
|
404
428
|
});
|
|
@@ -440,7 +464,7 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
440
464
|
}
|
|
441
465
|
};
|
|
442
466
|
refuseLabelsInQuery({ query: ctx.req.query() });
|
|
443
|
-
const { files: filesArray, fields } = await parseMultipartBody({
|
|
467
|
+
const { files: filesArray, fields } = await RequestUtility.parseMultipartBody({
|
|
444
468
|
context: ctx,
|
|
445
469
|
storage: options?.parseMultipartBody?.storage,
|
|
446
470
|
uploadDir: options?.parseMultipartBody?.uploadDir,
|
|
@@ -501,7 +525,7 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
501
525
|
defaultKey,
|
|
502
526
|
})
|
|
503
527
|
: defaultKey;
|
|
504
|
-
if (!
|
|
528
|
+
if (!AssetKeyScope.isInScope({ key, keyPrefix })) {
|
|
505
529
|
throw getError({
|
|
506
530
|
error: StaticAssetErrors.OBJECT_KEY_OUT_OF_SCOPE,
|
|
507
531
|
message: `Object key is outside the key prefix of this controller | key: ${key} | keyPrefix: ${keyPrefix}`,
|
|
@@ -510,7 +534,7 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
510
534
|
return key;
|
|
511
535
|
}
|
|
512
536
|
: options?.normalizeNameFn;
|
|
513
|
-
|
|
537
|
+
const result = await helper.upload({
|
|
514
538
|
bucket: { name: bucketName },
|
|
515
539
|
files: modifiedFiles,
|
|
516
540
|
normalizeNameFn,
|
|
@@ -518,6 +542,7 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
518
542
|
// Without this the helper re-validates against its own hard default of 2, so an app configured for a deeper tree spools the body and only then fails inside the helper.
|
|
519
543
|
maxFolderDepth: objectKeyMaxDepth,
|
|
520
544
|
});
|
|
545
|
+
uploaded = result;
|
|
521
546
|
}
|
|
522
547
|
finally {
|
|
523
548
|
this.removeSpoolFiles({ paths: spoolPaths });
|
|
@@ -532,7 +557,7 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
532
557
|
bucket: uploadResult.bucket,
|
|
533
558
|
object: uploadResult.object,
|
|
534
559
|
});
|
|
535
|
-
const createdMetaLink = await
|
|
560
|
+
const createdMetaLink = await AssetMetaLink.createRow({
|
|
536
561
|
metaLink,
|
|
537
562
|
helper,
|
|
538
563
|
storage,
|
|
@@ -560,7 +585,7 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
560
585
|
},
|
|
561
586
|
});
|
|
562
587
|
}
|
|
563
|
-
const deleteObjectRoute =
|
|
588
|
+
const deleteObjectRoute = AssetRouteOptions.readOverride({ route: routes?.deleteObject });
|
|
564
589
|
if (deleteObjectRoute.isEnabled) {
|
|
565
590
|
this.bindRoute({
|
|
566
591
|
configs: { ...definitions.DELETE_OBJECT, ...deleteObjectRoute.override },
|
|
@@ -582,7 +607,7 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
582
607
|
throw getError({ error: StaticAssetErrors.OBJECT_NAME_INVALID });
|
|
583
608
|
}
|
|
584
609
|
// Before any storage call: a key outside the scope must not even be probed.
|
|
585
|
-
|
|
610
|
+
AssetKeyScope.assertInScope({ key: objectName, keyPrefix });
|
|
586
611
|
// Deliberately idempotent: S3 answers 200 for a key that was never there, and consumers
|
|
587
612
|
// already depend on it. `disk` throws instead, so the two are reconciled here, not below.
|
|
588
613
|
try {
|
|
@@ -592,14 +617,16 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
592
617
|
});
|
|
593
618
|
}
|
|
594
619
|
catch (error) {
|
|
595
|
-
if (!isNotFoundError({ error })) {
|
|
620
|
+
if (!StorageUtility.isNotFoundError({ error })) {
|
|
596
621
|
throw error;
|
|
597
622
|
}
|
|
598
623
|
}
|
|
599
624
|
if (!useMetaLink || !metaLink) {
|
|
600
625
|
return ctx.json({ success: true }, HTTP.ResultCodes.RS_2.Ok);
|
|
601
626
|
}
|
|
602
|
-
const deleteRepository = await resolveValueAsync({
|
|
627
|
+
const deleteRepository = await ResolverUtility.resolveValueAsync({
|
|
628
|
+
value: metaLink.repository,
|
|
629
|
+
});
|
|
603
630
|
deleteRepository
|
|
604
631
|
.deleteAll({
|
|
605
632
|
where: {
|
|
@@ -621,7 +648,7 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
621
648
|
},
|
|
622
649
|
});
|
|
623
650
|
}
|
|
624
|
-
const listObjectsRoute =
|
|
651
|
+
const listObjectsRoute = AssetRouteOptions.readOverride({ route: routes?.listObjects });
|
|
625
652
|
if (listObjectsRoute.isEnabled) {
|
|
626
653
|
this.bindRoute({
|
|
627
654
|
configs: { ...definitions.LIST_OBJECTS, ...listObjectsRoute.override },
|
|
@@ -647,7 +674,7 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
647
674
|
});
|
|
648
675
|
}
|
|
649
676
|
}
|
|
650
|
-
const scoped =
|
|
677
|
+
const scoped = AssetKeyScope.resolveListPrefix({ prefix, keyPrefix });
|
|
651
678
|
if (scoped.isOutOfScope) {
|
|
652
679
|
return ctx.json([], HTTP.ResultCodes.RS_2.Ok);
|
|
653
680
|
}
|
|
@@ -670,13 +697,14 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
670
697
|
const pendingPrefix = directUpload.pendingPrefix ?? DEFAULT_PENDING_PREFIX;
|
|
671
698
|
// The scope rides inside the pending key, so the commit, which strips `pendingPrefix`, lands inside it.
|
|
672
699
|
const policyKeyPrefix = `${pendingPrefix}${keyPrefix ?? ''}`;
|
|
673
|
-
const uploadPolicyRoute =
|
|
700
|
+
const uploadPolicyRoute = AssetRouteOptions.readOverride({ route: routes?.uploadPolicy });
|
|
674
701
|
if (uploadPolicyRoute.isEnabled) {
|
|
675
702
|
this.bindRoute({
|
|
676
703
|
configs: { ...definitions.UPLOAD_POLICY, ...uploadPolicyRoute.override },
|
|
677
704
|
}).to({
|
|
678
705
|
handler: async (ctx) => {
|
|
679
|
-
|
|
706
|
+
const result = await directUpload.authorize({ context: ctx });
|
|
707
|
+
if (!result) {
|
|
680
708
|
throw getError({ error: StaticAssetErrors.UPLOAD_NOT_AUTHORIZED });
|
|
681
709
|
}
|
|
682
710
|
const { files } = ctx.req.valid('json');
|
|
@@ -702,7 +730,7 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
702
730
|
policies.push({
|
|
703
731
|
...policy,
|
|
704
732
|
objectName,
|
|
705
|
-
commitToken:
|
|
733
|
+
commitToken: AssetCommitToken.build({
|
|
706
734
|
payload: {
|
|
707
735
|
bucket: bucketName,
|
|
708
736
|
key: objectName,
|
|
@@ -716,7 +744,7 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
716
744
|
},
|
|
717
745
|
});
|
|
718
746
|
}
|
|
719
|
-
const uploadCommitRoute =
|
|
747
|
+
const uploadCommitRoute = AssetRouteOptions.readOverride({ route: routes?.uploadCommit });
|
|
720
748
|
if (uploadCommitRoute.isEnabled) {
|
|
721
749
|
this.bindRoute({
|
|
722
750
|
configs: { ...definitions.UPLOAD_COMMIT, ...uploadCommitRoute.override },
|
|
@@ -732,7 +760,7 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
732
760
|
const { commitToken, ...labels } = ctx.req.valid('json');
|
|
733
761
|
// Verified BEFORE any storage call. That is what keeps this route from being a name
|
|
734
762
|
// prober: a forged token fails without a round trip, so timing says nothing.
|
|
735
|
-
const payload =
|
|
763
|
+
const payload = AssetCommitToken.read({
|
|
736
764
|
token: commitToken,
|
|
737
765
|
secretKey: directUpload.secretKey,
|
|
738
766
|
});
|
|
@@ -743,7 +771,7 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
743
771
|
const pendingObject = { key: payload.key };
|
|
744
772
|
const object = { key: payload.key.slice(pendingPrefix.length) };
|
|
745
773
|
// A token another controller signed with the same secret must not land outside this scope.
|
|
746
|
-
|
|
774
|
+
AssetKeyScope.assertInScope({ key: object.key, keyPrefix });
|
|
747
775
|
// Before the copy, so a hook that throws leaves the object under the pending prefix
|
|
748
776
|
// for a lifecycle rule, rather than stranding it at the final key.
|
|
749
777
|
await directUpload.onCommit?.({ bucket: bucketRef, pendingObject, object });
|
|
@@ -762,7 +790,7 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
762
790
|
.for('UPLOAD_COMMIT')
|
|
763
791
|
.warn('Committed, but the pending object remains | key: %s | error: %s', pendingObject.key, error);
|
|
764
792
|
});
|
|
765
|
-
const link = buildObjectLink({
|
|
793
|
+
const link = AssetControllerFactory.buildObjectLink({
|
|
766
794
|
basePath: normalizedBasePath,
|
|
767
795
|
bucket: bucketRef,
|
|
768
796
|
object,
|
|
@@ -775,11 +803,11 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
775
803
|
if (useMetaLink && metaLink) {
|
|
776
804
|
try {
|
|
777
805
|
const fileStat = await helper.getStat({ bucket: bucketRef, object });
|
|
778
|
-
const data = await
|
|
806
|
+
const data = await AssetMetaLink.createRow({
|
|
779
807
|
metaLink,
|
|
780
808
|
helper,
|
|
781
809
|
storage,
|
|
782
|
-
uploadResult: buildStoredUploadResult({
|
|
810
|
+
uploadResult: AssetMetaLink.buildStoredUploadResult({
|
|
783
811
|
helper,
|
|
784
812
|
bucket: bucketRef,
|
|
785
813
|
object,
|
|
@@ -811,7 +839,9 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
811
839
|
}
|
|
812
840
|
}
|
|
813
841
|
if (useMetaLink && metaLink) {
|
|
814
|
-
const recreateMetaLinkRoute =
|
|
842
|
+
const recreateMetaLinkRoute = AssetRouteOptions.readOverride({
|
|
843
|
+
route: routes?.recreateMetaLink,
|
|
844
|
+
});
|
|
815
845
|
if (recreateMetaLinkRoute.isEnabled) {
|
|
816
846
|
this.bindRoute({
|
|
817
847
|
configs: { ...definitions.RECREATE_METALINK, ...recreateMetaLinkRoute.override },
|
|
@@ -838,20 +868,20 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
838
868
|
throw getError({ error: StaticAssetErrors.OBJECT_NAME_INVALID });
|
|
839
869
|
}
|
|
840
870
|
// Before any storage call: a key outside the scope must not even be probed.
|
|
841
|
-
|
|
871
|
+
AssetKeyScope.assertInScope({ key: objectName, keyPrefix });
|
|
842
872
|
const bucketRef = { name: bucketName };
|
|
843
873
|
const object = { key: objectName };
|
|
844
874
|
const fileStat = await helper.getStat({ bucket: bucketRef, object });
|
|
845
875
|
const link = options?.normalizeLinkFn
|
|
846
876
|
? options.normalizeLinkFn({ bucket: bucketRef, object })
|
|
847
|
-
: buildObjectLink({
|
|
877
|
+
: AssetControllerFactory.buildObjectLink({
|
|
848
878
|
basePath: normalizedBasePath,
|
|
849
879
|
bucket: bucketRef,
|
|
850
880
|
object,
|
|
851
881
|
hasConfiguredBucket,
|
|
852
882
|
rawObjectPath,
|
|
853
883
|
});
|
|
854
|
-
const refreshed = await
|
|
884
|
+
const refreshed = await AssetMetaLink.refreshRows({
|
|
855
885
|
metaLink,
|
|
856
886
|
helper,
|
|
857
887
|
bucket: bucketRef,
|
|
@@ -870,11 +900,11 @@ export class AssetControllerFactory extends BaseHelper {
|
|
|
870
900
|
}
|
|
871
901
|
// Not atomic with the refresh above: two concurrent calls may both create, which the
|
|
872
902
|
// table allows - rows per pair are deliberately not unique.
|
|
873
|
-
const created = await
|
|
903
|
+
const created = await AssetMetaLink.createRow({
|
|
874
904
|
metaLink,
|
|
875
905
|
helper,
|
|
876
906
|
storage,
|
|
877
|
-
uploadResult: buildStoredUploadResult({
|
|
907
|
+
uploadResult: AssetMetaLink.buildStoredUploadResult({
|
|
878
908
|
helper,
|
|
879
909
|
bucket: bucketRef,
|
|
880
910
|
object,
|