@filelayer/core 0.3.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.
Files changed (69) hide show
  1. package/CHANGELOG.md +338 -0
  2. package/LICENSE +202 -0
  3. package/MIGRATIONS.md +328 -0
  4. package/NOTICE +37 -0
  5. package/README.md +343 -0
  6. package/SEMANTICS.md +729 -0
  7. package/dist/authz.d.ts +524 -0
  8. package/dist/authz.d.ts.map +1 -0
  9. package/dist/authz.js +889 -0
  10. package/dist/authz.js.map +1 -0
  11. package/dist/db.d.ts +145 -0
  12. package/dist/db.d.ts.map +1 -0
  13. package/dist/db.js +217 -0
  14. package/dist/db.js.map +1 -0
  15. package/dist/delivery.d.ts +293 -0
  16. package/dist/delivery.d.ts.map +1 -0
  17. package/dist/delivery.js +519 -0
  18. package/dist/delivery.js.map +1 -0
  19. package/dist/errors.d.ts +16 -0
  20. package/dist/errors.d.ts.map +1 -0
  21. package/dist/errors.js +21 -0
  22. package/dist/errors.js.map +1 -0
  23. package/dist/filelayer.d.ts +542 -0
  24. package/dist/filelayer.d.ts.map +1 -0
  25. package/dist/filelayer.js +1360 -0
  26. package/dist/filelayer.js.map +1 -0
  27. package/dist/index.d.ts +8 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +8 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/simple.d.ts +297 -0
  32. package/dist/simple.d.ts.map +1 -0
  33. package/dist/simple.js +492 -0
  34. package/dist/simple.js.map +1 -0
  35. package/dist/storage.d.ts +269 -0
  36. package/dist/storage.d.ts.map +1 -0
  37. package/dist/storage.js +700 -0
  38. package/dist/storage.js.map +1 -0
  39. package/dist/store.d.ts +432 -0
  40. package/dist/store.d.ts.map +1 -0
  41. package/dist/store.js +862 -0
  42. package/dist/store.js.map +1 -0
  43. package/package.json +77 -0
  44. package/schema.sql +1190 -0
  45. package/src/authz.ts +1398 -0
  46. package/src/db.ts +271 -0
  47. package/src/delivery.ts +737 -0
  48. package/src/errors.ts +24 -0
  49. package/src/filelayer.ts +1836 -0
  50. package/src/index.ts +7 -0
  51. package/src/simple.ts +666 -0
  52. package/src/storage.ts +917 -0
  53. package/src/store.ts +1072 -0
  54. package/test/delivery.test.ts +0 -0
  55. package/test/group-subjects.test.ts +1072 -0
  56. package/test/helpers.ts +65 -0
  57. package/test/listing.test.ts +689 -0
  58. package/test/local-s3.d.mts +33 -0
  59. package/test/local-s3.mjs +400 -0
  60. package/test/persistence.test.ts +953 -0
  61. package/test/regression.test.ts +619 -0
  62. package/test/s3-live.test.ts +322 -0
  63. package/test/security.test.ts +1652 -0
  64. package/test/semantics.test.ts +888 -0
  65. package/test/storage.test.ts +437 -0
  66. package/test/tiers.test.ts +432 -0
  67. package/test/vault-example.test.ts +302 -0
  68. package/tsconfig.build.json +29 -0
  69. package/tsconfig.json +19 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,338 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@filelayer/core`.
4
+
5
+ Format loosely follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
+ Versioning is pre-1.0 and is explained in [`MIGRATIONS.md`](MIGRATIONS.md) §1.
7
+
8
+ ## A note on honesty, before the entries
9
+
10
+ **No version of this package has been published to npm.** The versions below are
11
+ real, dated development milestones in this repository, not registry releases. We
12
+ are writing them up as a changelog rather than starting the history at the first
13
+ publish because a consumer deciding whether to depend on a `0.x` library is
14
+ entitled to know what has already moved underneath it, and because most of the
15
+ entries are security defects we found in our own code.
16
+
17
+ They are described the way we found them, including the ones that were
18
+ embarrassing. A changelog that only records features is a marketing document.
19
+
20
+ `0.3.0` is the version prepared for the first publish.
21
+
22
+ ---
23
+
24
+ ## [Unreleased] — group grant subjects (RFC-001)
25
+
26
+ Breaking schema change, additive API. Migration: `MIGRATIONS.md` Entry 2.
27
+
28
+ ### Fixed
29
+
30
+ - **A byte range could be sent as `HTTP 200`, which is silent data corruption.**
31
+ `readStream()` and `redeemStream()` accept a byte range and attach
32
+ `Content-Range` when the store serves one, but `sendNodeStream()` and
33
+ `toStreamResponse()` both hardcoded `200`. Anyone following the documented
34
+ advice to wire the `Range` request header themselves emitted a **truncated
35
+ body under a 200** — which every HTTP client treats as the complete
36
+ representation, so it is cached, hashed and handed on with no error anywhere.
37
+ Both writers now derive the status from the delivery: `206` with
38
+ `Content-Range` when a range was served, `200` otherwise. There is deliberately
39
+ no status parameter — there is no value a caller could supply that the writer
40
+ does not already know, and every value they could supply by mistake is wrong.
41
+ Covered by four tests in `test/delivery.test.ts`.
42
+
43
+ ### Added
44
+
45
+ - **`grant_subject := actor | org | role | link | anonymous`.** A grant's
46
+ subject is a principal set, and `org` / `role` are the missing middle between
47
+ "one person" and "everyone". Two new columns on `file_grant`,
48
+ `subject_org_id` and `subject_min_role`.
49
+ - **Resolution is a join, never a materialization.** Adding or removing an org
50
+ member changes access on the very next request, with no recomputation and no
51
+ write to any grant row. Asserted by fingerprinting every `file_grant` row
52
+ across a join, a leave and a role change.
53
+ - **Cross-org grants inside a project are the point** ("the company that
54
+ posted this job may read this CV"). Cross-**project** ones are
55
+ unrepresentable, by composite foreign key.
56
+ - No custom groups, no nested orgs, no configurable inheritance, no deny
57
+ rules. `subject_min_role` is only a threshold over the existing
58
+ `viewer | member | admin | owner` enum.
59
+ - **I6 — subject breadth may not be amplified by delegation.** An issuer whose
60
+ authority is role-derived may mint any subject type; an issuer whose authority
61
+ is grant-derived may mint only `actor` or `link`. Enforced in
62
+ `authorizeShare()` (reason `subject_breadth_amplification`, `403`, audited)
63
+ **and** in the `file_grant_attenuate()` trigger (`grant_subject_amplification`),
64
+ so it binds a caller issuing raw SQL. The trigger now also fires on the subject
65
+ columns, so a delegated grant cannot be widened by a later `UPDATE`.
66
+ - `AuthzPath` gains `grant:org` and `grant:role`. Group allows carry `viaOrgId`,
67
+ `viaMinRole` and `viaRole` in the audit context, so a compliance auditor can
68
+ see which membership conferred access.
69
+ - `shares.create(fileId, { as, withOrg, minRole })` on the tiered API.
70
+ `withOrg` does **not** auto-provision a tenant: an unknown org is `404`.
71
+
72
+ ### Changed
73
+
74
+ - `grant_scope_is_live()` takes a fourth argument and gains one term: a grant is
75
+ live only while its **subject org** is live (I2). Deleting an org now kills the
76
+ grants held by its members, as it already killed the grants on its files.
77
+ - `file.visibility = 'org'` is **retained**, and is now describable as an
78
+ implicit org grant.
79
+
80
+ ### Fixed
81
+
82
+ - **`getActorGrants` had no `ORDER BY`, and the delegation parent depended on
83
+ it.** `resolveStanding` attributes an allow to the first returned grant
84
+ carrying the requested capability, and on the share path that grant becomes
85
+ the child's `parent_grant_id` — the ceiling the attenuation trigger measures
86
+ against. With no ordering, Postgres returned heap order, which is undefined
87
+ and moves with page layout, `VACUUM` and row width. A principal holding
88
+ several grants on one file could therefore have `share()` succeed or fail
89
+ depending on physical storage. Fail-closed, never a disclosure, but not a
90
+ semantics anyone could document. Now ordered oldest-first. Found while adding
91
+ the columns above, which was enough to flip it.
92
+
93
+ ### Known, recorded rather than hidden
94
+
95
+ - `authorizeShare` computes the issuer's held capabilities as the **union** over
96
+ every source, while `parent_grant_id` is a **single** grant. A principal
97
+ holding several grants on one file can therefore be approved for a capability
98
+ set that no one ancestor covers, and the attenuation trigger then refuses the
99
+ insert. The outcome is a `403` rather than a disclosure, so P4 is intact; what
100
+ is wrong is that a legitimate delegation can be refused. Closing it means
101
+ changing the delegation model (pick a covering parent, or mint one child per
102
+ contributing ancestor) and was out of scope for RFC-001.
103
+
104
+ ---
105
+
106
+ ## [0.3.0] — 2026-09-05
107
+
108
+ The release that makes the package installable, and the one that closes the
109
+ last cross-tenant defect.
110
+
111
+ ### Added
112
+
113
+ - **Compiled output.** The package now ships `dist/` (JavaScript plus `.d.ts`)
114
+ and its `exports` point at it. Previously `exports` pointed at `src/index.ts`,
115
+ which is not importable from an install: Node refuses to strip types from
116
+ files under `node_modules`
117
+ (`ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING`). The package was installable
118
+ and unusable.
119
+ - **The TypeScript source and the full test suite ship in the tarball**, so
120
+ every claim in the README is inspectable from what you installed. They cannot
121
+ be *run* from `node_modules` for the reason above; clone the repository.
122
+ - `SEMANTICS.md`, `MIGRATIONS.md`, `CHANGELOG.md` and `LICENSE` are in the
123
+ tarball.
124
+ - **A transaction abstraction.** `withTransaction()`, `Tx`, and `Queryable`
125
+ gaining an optional `withTransaction` hook. `pg.Pool` is now used through
126
+ `connect()`, so a transaction stays on one connection instead of scattering
127
+ across the pool.
128
+ - **Streaming.** `upload()` accepts a `ReadableStream`; the storage interface
129
+ gained `stream()`, `head()` and an optional `list()`; delivery can stream
130
+ rather than buffer. `toStreamResponse()` returns a streaming WHATWG
131
+ `Response`.
132
+ - **Byte-range reads** at the storage and delivery API level. The shipped HTTP
133
+ route helpers still do not parse the `Range` request header and never return
134
+ `206`.
135
+ - **Redirect delivery** — an opt-in mode that hands out a short-lived presigned
136
+ URL instead of proxying bytes, for deployments that need a CDN. Off by
137
+ default; restricted to anonymous grants unless widened; requires passing a
138
+ verbatim acknowledgement constant, because it trades a bounded revocation
139
+ window for the byte path and that trade must be made deliberately.
140
+ - `collectStorageOrphans()` — collection for objects written by an upload whose
141
+ metadata never committed.
142
+
143
+ ### Fixed
144
+
145
+ - **Cross-project identity collision (HIGH).** `org.external_id` and
146
+ `actor.external_id` were globally unique. In any deployment where more than
147
+ one application shares a database, application B calling `put({ org: 'acme'
148
+ })` did not get an error — it got application A's org id, and the identity
149
+ resolver then added B's user to A's tenant as a `member`. Same shape for
150
+ actors, so `as: 'alice'` resolved across the boundary too. A complete
151
+ cross-tenant compromise reachable from the most ergonomic entry point in the
152
+ library. Fixed by introducing a **project** scope above the tenant and making
153
+ every access-bearing table carry `project_id` under a composite foreign key,
154
+ so a cross-project row is unrepresentable rather than merely unlikely.
155
+ **Breaking schema change — see [`MIGRATIONS.md`](MIGRATIONS.md) entry 1.**
156
+ - **A soft-deleted org stopped conferring membership but did not kill
157
+ outstanding grants.** Deleting a tenant removed the owner's access and left a
158
+ contractor's share link serving bytes. Nobody chose that; it was an emergent
159
+ asymmetry between two store methods, found because the set query and the point
160
+ check disagreed. Grant liveness is now a predicate over the whole scope — the
161
+ file, its org, that org's project, the subject actor and the issuing actor —
162
+ evaluated on every request, with no cascading write, so a restore revives
163
+ exactly what the delete killed.
164
+ - **`maxDownloads` was charged only on the share-link path.** An actor grant
165
+ carrying `maxDownloads: 3` permitted unlimited direct authenticated reads,
166
+ because nothing on that path touched the counter. The field meant "link
167
+ redemptions" on one path and nothing at all on the other, while being named,
168
+ documented and billed as a download cap. A download is now charged whenever
169
+ bytes leave through a grant, by any principal, on any path. Authority derived
170
+ from an org role is not charged (a role is not a metered credential) and
171
+ metadata reads are not charged (no bytes leave).
172
+ - **The audit hash chain could fork under concurrent writers.** It was built
173
+ with a `SELECT` of the last hash followed by an `INSERT`, from application
174
+ code, in two statements — atomic only under a single serialized writer. It is
175
+ now one call to `audit_append()`, which takes `pg_advisory_xact_lock` on the
176
+ chain, reads the predecessor and inserts, inside one statement. The library
177
+ runs that in the same transaction as the mutation it describes, so the lock
178
+ covers both. Caveat stated plainly: the suite runs on PGlite, which has one
179
+ backend, so the test proves the lock is taken on the write path — the
180
+ multi-process argument rests on Postgres advisory-lock semantics.
181
+ - **The audit write was not in the same transaction as the thing it audited.**
182
+ `put()` performed five independent statements; a failure after the second left
183
+ a file with no audit record. For a product whose selling point is a
184
+ tamper-evident trail, an intact chain that simply does not mention what
185
+ happened is a hole in the premise.
186
+ - **`file.storage_provider` was written as the literal `'memory'` on every
187
+ insert**, regardless of the configured adapter, so a production deployment
188
+ recorded every object as living in an in-process map. It participates in a
189
+ unique index with the key and is therefore half of an object's identity, not a
190
+ label.
191
+ - **Unauthenticated audit-chain growth is now bounded.** A caller probing org
192
+ ids can only reach a tenant chain inside a project they are already
193
+ authenticated for; probes at every other id land on the system chain. Still
194
+ requires rate limiting at ingest — denials are audited by design and that is
195
+ not negotiable — but the reach went from "any internet caller, any tenant" to
196
+ "an authenticated customer, their own tenant".
197
+
198
+ ### Changed
199
+
200
+ - **Breaking:** the schema requires a `project` row. A default project is
201
+ inserted by `schema.sql`, so a single-application deployment needs no project
202
+ vocabulary.
203
+ - **Breaking:** `engines.node` is `>=22.18` and enforced.
204
+ - **Licensed under Apache-2.0.** `license` was `UNLICENSED` and `LICENSE` was an
205
+ explicit placeholder granting no rights; both are resolved before this version
206
+ is published. `LICENSE` is now the verbatim Apache License 2.0 and ships in
207
+ the tarball alongside a `NOTICE` file, so the grant travels with the package
208
+ rather than only with the repository. See
209
+ [LICENSE](https://github.com/filelayer/filelayer/blob/main/LICENSE) and
210
+ [NOTICE](https://github.com/filelayer/filelayer/blob/main/NOTICE).
211
+ - Scratch and diagnostic scripts moved out of the package root into `dev/` and
212
+ are excluded from the tarball. The `package.json` scripts that referenced them
213
+ moved to the repository root.
214
+ - Documentation was swept of internal review vocabulary, and a CI check now
215
+ fails the build if it comes back.
216
+
217
+ ### Known limitations at this version
218
+
219
+ Listed in the README, and repeated here because a changelog that only records
220
+ wins is not one: no `Range` responses from the shipped routes; no direct
221
+ browser-to-storage upload; org admins can read `private` files; identifiers are
222
+ per-project, not per-org; the S3/R2 adapter has never run against live
223
+ credentials; orphan collection and ingest rate limiting are jobs you schedule.
224
+
225
+ ---
226
+
227
+ ## [0.2.0] — 2026-09-05
228
+
229
+ The security rebuild. Twelve defects found by an independent review of the
230
+ authorization core plus five found while fixing them. This is the release where
231
+ the delivery layer stopped being the developer's problem.
232
+
233
+ ### Fixed — authorization
234
+
235
+ - **A delegated grant outlived the grant that created it (HIGH).** Revoking a
236
+ grant left everything delegated from it alive, which meant the central claim —
237
+ a URL never outlives its permission — was true only for directly-issued
238
+ grants. Liveness is now evaluated over the whole ancestor chain, in the
239
+ schema, so revocation is transitive at any depth with no cascading write.
240
+ - **Capability amplification through `share` (HIGH).** A holder of `read` could
241
+ mint a grant carrying `delete`. Attenuation is now enforced by the
242
+ authorization engine *and* again by a `BEFORE INSERT` trigger, so it binds a
243
+ migration or a `psql` session as well as an API call.
244
+ - **Membership management had no authorization and no audit (HIGH).** Anyone who
245
+ could reach the method could change anyone's role. Now: you may not grant a
246
+ role above your own, may not modify anyone who outranks you, may not remove
247
+ the last owner, and every attempt — allowed or denied — is audited.
248
+ - **Holding `share` conferred revoke over every grant on the file.** A
249
+ contractor given the ability to share could revoke the owner's grants.
250
+ Narrowed to the grants in your own delegation subtree.
251
+ - **A `link` grant could carry `delete`.** A leaked share link could destroy the
252
+ file it pointed at. Share links are read-only by database constraint now.
253
+
254
+ ### Fixed — the audit trail
255
+
256
+ - **Enumeration left no trace (HIGH).** Decisions that could not be attributed
257
+ to a tenant — a probe against a file id that does not exist, a sweep against
258
+ link secrets — were dropped rather than recorded, which made exactly the
259
+ reconnaissance the log exists to catch invisible. They now go to a system
260
+ chain (`org_id IS NULL`) that no tenant can read.
261
+ - **An exhausted download cap was not audited.** "Why did my link stop working"
262
+ was unanswerable from the log.
263
+ - **The hash chain did not cover the forensic fields.** The digest covered seven
264
+ columns; `reason`, `grant_id`, `ip`, `user_agent` and `context` — the fields an
265
+ incident responder relies on and an attacker would rewrite — were outside the
266
+ commitment, which made the chain decorative for the questions that matter. The
267
+ digest now covers every forensically relevant column, encoded as canonical
268
+ JSON rather than concatenated, because concatenation lets a forger shift field
269
+ boundaries.
270
+ - **A well-formed but unregistered actor id crashed the audit write (HIGH).**
271
+ `audit_event.actor_id` carried a foreign key to `actor`, so a caller
272
+ presenting an unknown-but-valid id could not be audited at all: the insert
273
+ raised, the exception propagated out of `authorize()`, the denial was never
274
+ recorded, and the caller got a 500 where a real stranger gets a 404 — an
275
+ actor-existence oracle and a silent hole in the denial log, at once. The
276
+ foreign key is gone; recording identifiers that do not exist is the audit
277
+ log's job.
278
+
279
+ ### Fixed — the error surface and delivery
280
+
281
+ - **The error surface was an existence oracle.** Denials are now uniformly 404
282
+ and the evaluation order that makes that true is itself a security property.
283
+ - **`Content-Disposition` filenames were interpolated, not encoded** — response
284
+ splitting through an uploaded filename. On one comparison implementation the
285
+ same bug turns every share download of an affected document into a permanent
286
+ 500.
287
+ - **`upload()` took a bare actor id (HIGH)**, so ownership was forgeable from a
288
+ request body. It takes an authorized principal now.
289
+ - **Byte delivery was the developer's problem (HIGH).** `read()` returned a
290
+ `Uint8Array` and the application chose `Content-Type`,
291
+ `Content-Disposition`, `X-Content-Type-Options` and `Cache-Control` — three
292
+ security-sensitive decisions handed back to the developer by a library
293
+ claiming to have removed them, and the example got them wrong. `get()` now
294
+ returns `headers`, computed from the file record, with no option to disable
295
+ them.
296
+ - **A credential could be passed in a share-link query string.** Refused with
297
+ `400 credential_in_query`, before any work, without consuming a download.
298
+ Query strings end up in access logs, proxy logs and browser history.
299
+
300
+ ### Added
301
+
302
+ - **An authorized listing primitive (HIGH — its absence was the defect).** There
303
+ was no way to ask "which files may this caller see?", so building a listing
304
+ screen meant hand-rolling the org filter, the visibility rule, the owner
305
+ check, the role check and a union over the grant table in application SQL.
306
+ `listFiles()` answers it in one query and one audit event, with no filter
307
+ parameter to forget. `test/listing.test.ts` asserts set equality against
308
+ `authorize()` over a randomized corpus on every capability, every run — a set
309
+ query that is too wide *or* too narrow fails the build.
310
+ - **File-level `visibility`.** Every member of an org could previously read
311
+ every file in it. Files are now `private` by default — owner and org admins
312
+ only — and org-wide visibility is something the creator asks for.
313
+
314
+ ### Known and reported, not fixed at this version
315
+
316
+ - `authorize()` is file-scoped, so creation authorization sits outside it.
317
+ Narrowed to a single `authorizeOrg('create_file')` call, not eliminated.
318
+ - Unauthenticated callers can append denial events to a known tenant's audit
319
+ chain. Bounded in 0.3.0.
320
+ - `maxDownloads` charged only on redemption. Fixed in 0.3.0.
321
+ - The audit chain could fork under concurrent writers. Fixed in 0.3.0.
322
+ - A soft-deleted org left outstanding grants alive. Fixed in 0.3.0.
323
+
324
+ ---
325
+
326
+ ## [0.1.0] — 2026-09-04
327
+
328
+ Initial implementation.
329
+
330
+ - The data model: projects had not been invented yet, so orgs, actors, files,
331
+ memberships, grants and a hash-chained audit log, with tenant isolation
332
+ enforced by composite foreign key rather than by `WHERE` clause.
333
+ - The authorization engine: one decision core, reached from a point check.
334
+ - The tiered facade — `files`, `orgs`, `shares` — over it.
335
+ - `MemoryStorage`, and an S3/R2 adapter that had not been run against anything.
336
+ - Share links with expiry, password and download cap.
337
+
338
+ Every defect in the 0.2.0 list above was present in this version.
package/LICENSE ADDED
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.